2 Bacula(R) - The Network Backup Solution
4 Copyright (C) 2000-2017 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.
20 * Bacula File Daemon backup.c send file attributes and data
21 * to the Storage daemon.
23 * Kern Sibbald, March MM
32 const bool have_lzo = true;
34 const bool have_lzo = false;
38 const bool have_libz = true;
40 const bool have_libz = false;
43 /* Forward referenced functions */
44 int save_file(JCR *jcr, FF_PKT *ff_pkt, bool top_level);
45 static int send_data(bctx_t &bctx, int stream);
46 static void close_vss_backup_session(JCR *jcr);
48 static bool send_resource_fork(bctx_t &bctx);
50 static bool setup_compression(bctx_t &bctx);
51 static bool do_lzo_compression(bctx_t &bctx);
52 static bool do_libz_compression(bctx_t &bctx);
55 * Find all the requested files and send them
56 * to the Storage daemon.
58 * Note, we normally carry on a one-way
59 * conversation from this point on with the SD, simply blasting
60 * data to him. To properly know what is going on, we
61 * also run a "heartbeat" monitor which reads the socket and
62 * reacts accordingly (at the moment it has nothing to do
63 * except echo the heartbeat to the Director).
66 bool blast_data_to_storage_daemon(JCR *jcr, char *addr)
70 // TODO landonf: Allow user to specify encryption algorithm
72 sd = jcr->store_bsock;
74 jcr->setJobStatus(JS_Running);
76 Dmsg1(300, "bfiled: opened data connection %d to stored\n", sd->m_fd);
79 CLIENT *client = (CLIENT *)GetNextRes(R_CLIENT, NULL);
83 buf_size = client->max_network_buffer_size;
85 buf_size = 0; /* use default */
87 if (!sd->set_buffer_size(buf_size, BNET_SETBUF_WRITE)) {
88 jcr->setJobStatus(JS_ErrorTerminated);
89 Jmsg(jcr, M_FATAL, 0, _("Cannot set buffer size FD->SD.\n"));
93 jcr->buf_size = sd->msglen;
95 * Adjust for compression so that output buffer is
96 * 12 bytes + 0.1% larger than input buffer plus 18 bytes.
97 * This gives a bit extra plus room for the sparse addr if any.
98 * Note, we adjust the read size to be smaller so that the
99 * same output buffer can be used without growing it.
101 * For LZO1X compression the recommended value is :
102 * output_block_size = input_block_size + (input_block_size / 16) + 64 + 3 + sizeof(comp_stream_header)
104 * The zlib compression workset is initialized here to minimize
105 * the "per file" load. The jcr member is only set, if the init
108 * For the same reason, lzo compression is initialized here.
111 jcr->compress_buf_size = MAX(jcr->buf_size + (jcr->buf_size / 16) + 67 + (int)sizeof(comp_stream_header), jcr->buf_size + ((jcr->buf_size+999) / 1000) + 30);
112 jcr->compress_buf = get_memory(jcr->compress_buf_size);
114 jcr->compress_buf_size = jcr->buf_size + ((jcr->buf_size+999) / 1000) + 30;
115 jcr->compress_buf = get_memory(jcr->compress_buf_size);
119 z_stream *pZlibStream = (z_stream*)malloc(sizeof(z_stream));
121 pZlibStream->zalloc = Z_NULL;
122 pZlibStream->zfree = Z_NULL;
123 pZlibStream->opaque = Z_NULL;
124 pZlibStream->state = Z_NULL;
126 if (deflateInit(pZlibStream, Z_DEFAULT_COMPRESSION) == Z_OK) {
127 jcr->pZLIB_compress_workset = pZlibStream;
135 lzo_voidp pLzoMem = (lzo_voidp) malloc(LZO1X_1_MEM_COMPRESS);
137 if (lzo_init() == LZO_E_OK) {
138 jcr->LZO_compress_workset = pLzoMem;
145 if (!crypto_session_start(jcr)) {
149 set_find_options(jcr->ff, jcr->incremental, jcr->mtime);
150 set_find_snapshot_function(jcr->ff, snapshot_convert_path);
152 /** in accurate mode, we overload the find_one check function */
154 set_find_changed_function((FF_PKT *)jcr->ff, accurate_check_file);
156 start_heartbeat_monitor(jcr);
158 jcr->xacl = (XACL*)new_xacl();
160 /* Subroutine save_file() is called for each file */
161 if (!find_files(jcr, (FF_PKT *)jcr->ff, save_file, plugin_save)) {
162 ok = false; /* error */
163 jcr->setJobStatus(JS_ErrorTerminated);
167 if (jcr->xacl->get_acl_nr_errors() > 0) {
168 Jmsg(jcr, M_WARNING, 0, _("Had %ld acl errors while doing backup\n"),
169 jcr->xacl->get_acl_nr_errors());
171 if (jcr->xacl->get_xattr_nr_errors() > 0) {
172 Jmsg(jcr, M_WARNING, 0, _("Had %ld xattr errors while doing backup\n"),
173 jcr->xacl->get_xattr_nr_errors());
176 /* Delete or keep snapshots */
177 close_snapshot_backup_session(jcr);
178 close_vss_backup_session(jcr);
180 accurate_finish(jcr); /* send deleted or base file list to SD */
182 stop_heartbeat_monitor(jcr);
184 sd->signal(BNET_EOD); /* end of sending data */
191 bfree_and_null(jcr->big_buf);
193 if (jcr->compress_buf) {
194 free_and_null_pool_memory(jcr->compress_buf);
196 if (jcr->pZLIB_compress_workset) {
197 /* Free the zlib stream */
199 deflateEnd((z_stream *)jcr->pZLIB_compress_workset);
201 bfree_and_null(jcr->pZLIB_compress_workset);
203 if (jcr->LZO_compress_workset) {
204 bfree_and_null(jcr->LZO_compress_workset);
207 crypto_session_end(jcr);
210 Dmsg1(100, "end blast_data ok=%d\n", ok);
216 * Called here by find() for each file included.
217 * This is a callback. The original is find_files() above.
219 * Send the file and its data to the Storage daemon.
223 * -1 to ignore file/directory (not used here)
225 int save_file(JCR *jcr, FF_PKT *ff_pkt, bool top_level)
227 bool do_read = false;
228 bool plugin_started = false;
229 bool do_plugin_set = false;
232 bool has_file_data = false;
233 struct save_pkt sp; /* used by option plugin */
234 BSOCK *sd = jcr->store_bsock;
235 bctx_t bctx; /* backup context */
237 memset(&bctx, 0, sizeof(bctx));
239 bctx.ff_pkt = ff_pkt;
243 time_t now = time(NULL);
244 if (jcr->last_stat_time == 0) {
245 jcr->last_stat_time = now;
246 jcr->stat_interval = 30; /* Default 30 seconds */
247 } else if (now >= jcr->last_stat_time + jcr->stat_interval) {
248 jcr->dir_bsock->fsend("Progress JobId=x files=%ld bytes=%lld bps=%ld\n",
249 jcr->JobFiles, jcr->JobBytes, jcr->LastRate);
250 jcr->last_stat_time = now;
253 if (jcr->is_canceled() || jcr->is_incomplete()) {
254 Dmsg0(100, "Job canceled by user or marked incomplete.\n");
258 jcr->num_files_examined++; /* bump total file count */
260 switch (ff_pkt->type) {
261 case FT_LNKSAVED: /* Hard linked, file already saved */
262 Dmsg2(130, "FT_LNKSAVED hard link: %s => %s\n", ff_pkt->fname, ff_pkt->link);
265 Dmsg1(130, "FT_REGE saving: %s\n", ff_pkt->fname);
266 has_file_data = true;
269 Dmsg1(130, "FT_REG saving: %s\n", ff_pkt->fname);
270 has_file_data = true;
273 Dmsg2(130, "FT_LNK saving: %s -> %s\n", ff_pkt->fname, ff_pkt->link);
275 case FT_RESTORE_FIRST:
276 Dmsg1(100, "FT_RESTORE_FIRST saving: %s\n", ff_pkt->fname);
278 case FT_PLUGIN_CONFIG:
279 Dmsg1(100, "FT_PLUGIN_CONFIG saving: %s\n", ff_pkt->fname);
282 jcr->num_files_examined--; /* correct file count */
283 return 1; /* not used */
285 Jmsg(jcr, M_INFO, 1, _(" Recursion turned off. Will not descend from %s into %s\n"),
286 ff_pkt->top_fname, ff_pkt->fname);
287 ff_pkt->type = FT_DIREND; /* Backup only the directory entry */
290 /* Suppress message for /dev filesystems */
291 if (!is_in_fileset(ff_pkt)) {
292 Jmsg(jcr, M_INFO, 1, _(" %s is a different filesystem. Will not descend from %s into it.\n"),
293 ff_pkt->fname, ff_pkt->top_fname);
295 ff_pkt->type = FT_DIREND; /* Backup only the directory entry */
298 Jmsg(jcr, M_INFO, 1, _(" Disallowed filesystem. Will not descend from %s into %s\n"),
299 ff_pkt->top_fname, ff_pkt->fname);
300 ff_pkt->type = FT_DIREND; /* Backup only the directory entry */
303 Jmsg(jcr, M_INFO, 1, _(" Disallowed drive type. Will not descend into %s\n"),
309 Dmsg1(130, "FT_DIREND: %s\n", ff_pkt->link);
312 Dmsg1(130, "FT_SPEC saving: %s\n", ff_pkt->fname);
313 if (S_ISSOCK(ff_pkt->statp.st_mode)) {
314 Jmsg(jcr, M_SKIPPED, 1, _(" Socket file skipped: %s\n"), ff_pkt->fname);
319 Dmsg1(130, "FT_RAW saving: %s\n", ff_pkt->fname);
320 has_file_data = true;
323 Dmsg1(130, "FT_FIFO saving: %s\n", ff_pkt->fname);
327 Jmsg(jcr, M_NOTSAVED, 0, _(" Could not access \"%s\": ERR=%s\n"), ff_pkt->fname,
328 be.bstrerror(ff_pkt->ff_errno));
334 Jmsg(jcr, M_NOTSAVED, 0, _(" Could not follow link \"%s\": ERR=%s\n"),
335 ff_pkt->fname, be.bstrerror(ff_pkt->ff_errno));
341 Jmsg(jcr, M_NOTSAVED, 0, _(" Could not stat \"%s\": ERR=%s\n"), ff_pkt->fname,
342 be.bstrerror(ff_pkt->ff_errno));
348 Jmsg(jcr, M_SKIPPED, 1, _(" Unchanged file skipped: %s\n"), ff_pkt->fname);
351 Jmsg(jcr, M_NOTSAVED, 0, _(" Archive file not saved: %s\n"), ff_pkt->fname);
355 Jmsg(jcr, M_NOTSAVED, 0, _(" Could not open directory \"%s\": ERR=%s\n"),
356 ff_pkt->fname, be.bstrerror(ff_pkt->ff_errno));
361 Dmsg1(130, "FT_DELETED: %s\n", ff_pkt->fname);
364 Jmsg(jcr, M_NOTSAVED, 0, _(" Unknown file type %d; not saved: %s\n"),
365 ff_pkt->type, ff_pkt->fname);
370 Dmsg1(130, "bfiled: sending %s to stored\n", ff_pkt->fname);
372 /** Digests and encryption are only useful if there's file data */
373 if (has_file_data && !crypto_setup_digests(bctx)) {
377 /** Initialize the file descriptor we use for data and other streams. */
379 if (ff_pkt->flags & FO_PORTABLE) {
380 set_portable_backup(&ff_pkt->bfd); /* disable Win32 BackupRead() */
383 if (ff_pkt->cmd_plugin) {
384 do_plugin_set = true;
386 /* option and cmd plugin are not compatible together */
387 } else if (ff_pkt->opt_plugin) {
389 /* ask the option plugin what to do with this file */
390 switch (plugin_option_handle_file(jcr, ff_pkt, &sp)) {
392 Dmsg2(10, "Option plugin %s will be used to backup %s\n",
393 ff_pkt->plugin, ff_pkt->fname);
394 do_plugin_set = true;
397 Dmsg2(10, "Option plugin %s decided to skip %s\n",
398 ff_pkt->plugin, ff_pkt->fname);
401 Dmsg2(10, "Option plugin %s decided to let bacula handle %s\n",
402 ff_pkt->plugin, ff_pkt->fname);
408 /* Tell bfile that it needs to call plugin */
409 if (!set_cmd_plugin(&ff_pkt->bfd, jcr)) {
412 send_plugin_name(jcr, sd, true); /* signal start of plugin data */
413 plugin_started = true;
416 /** Send attributes -- must be done after binit() */
417 if (!encode_and_send_attributes(bctx)) {
420 /** Meta data only for restore object */
421 if (IS_FT_OBJECT(ff_pkt->type)) {
424 /** Meta data only for deleted files */
425 if (ff_pkt->type == FT_DELETED) {
428 /** Set up the encryption context and send the session data to the SD */
429 if (has_file_data && jcr->crypto.pki_encrypt) {
430 if (!crypto_session_send(jcr, sd)) {
436 * Open any file with data that we intend to save, then save it.
438 * Note, if is_win32_backup, we must open the Directory so that
439 * the BackupRead will save its permissions and ownership streams.
441 if (ff_pkt->type != FT_LNKSAVED && S_ISREG(ff_pkt->statp.st_mode)) {
443 do_read = !is_portable_backup(&ff_pkt->bfd) || ff_pkt->statp.st_size > 0;
445 do_read = ff_pkt->statp.st_size > 0;
447 } else if (ff_pkt->type == FT_RAW || ff_pkt->type == FT_FIFO ||
448 ff_pkt->type == FT_REPARSE || ff_pkt->type == FT_JUNCTION ||
449 (!is_portable_backup(&ff_pkt->bfd) && ff_pkt->type == FT_DIREND)) {
453 if (ff_pkt->cmd_plugin && !ff_pkt->no_read) {
457 Dmsg2(150, "type=%d do_read=%d\n", ff_pkt->type, do_read);
461 if (ff_pkt->type == FT_FIFO) {
462 tid = start_thread_timer(jcr, pthread_self(), 60);
466 int noatime = ff_pkt->flags & FO_NOATIME ? O_NOATIME : 0;
467 ff_pkt->bfd.reparse_point = (ff_pkt->type == FT_REPARSE ||
468 ff_pkt->type == FT_JUNCTION);
469 set_fattrs(&ff_pkt->bfd, &ff_pkt->statp);
470 if (bopen(&ff_pkt->bfd, ff_pkt->fname, O_RDONLY | O_BINARY | noatime, 0) < 0) {
471 ff_pkt->ff_errno = errno;
473 Jmsg(jcr, M_NOTSAVED, 0, _(" Cannot open \"%s\": ERR=%s.\n"), ff_pkt->fname,
477 stop_thread_timer(tid);
483 stop_thread_timer(tid);
487 stat = send_data(bctx, bctx.data_stream);
489 if (ff_pkt->flags & FO_CHKCHANGES) {
490 has_file_changed(jcr, ff_pkt);
493 bclose(&ff_pkt->bfd);
500 #ifdef HAVE_DARWIN_OS
501 if (!send_resource_fork(bctx)) {
507 * Save ACLs and Extended Attributes when requested and available
508 * for anything not being a symlink and not being a plugin (why not?).
511 if (jcr->xacl->backup_acl(jcr, ff_pkt) == bRC_XACL_error) {
514 if (jcr->xacl->backup_xattr(jcr, ff_pkt) == bRC_XACL_error) {
519 if (!crypto_terminate_digests(bctx)) {
527 if (jcr->is_incomplete() || jcr->is_canceled()) {
528 Dmsg0(100, "Job canceled by user or marked incomplete.\n");
531 if (plugin_started) {
532 send_plugin_name(jcr, sd, false); /* signal end of plugin data */
534 if (ff_pkt->opt_plugin) {
535 jcr->plugin_sp = NULL; /* sp is local to this function */
536 jcr->plugin_ctx = NULL;
538 jcr->opt_plugin = false;
545 * Send data read from an already open file descriptor.
547 * We return 1 on success and 0 on errors.
550 * We use ff_pkt->statp.st_size when FO_SPARSE to know when to stop
552 * Currently this is not a problem as the only other stream, resource forks,
553 * are not handled as sparse files.
555 static int send_data(bctx_t &bctx, int stream)
558 BSOCK *sd = jcr->store_bsock;
560 #ifdef FD_NO_SEND_TEST
564 bctx.rsize = jcr->buf_size;
566 bctx.cipher_ctx = NULL;
567 bctx.msgsave = sd->msg;
568 bctx.rbuf = sd->msg; /* read buffer */
569 bctx.wbuf = sd->msg; /* write buffer */
570 bctx.cipher_input = (uint8_t *)bctx.rbuf; /* encrypt uncompressed data */
572 Dmsg1(300, "Saving data, type=%d\n", bctx.ff_pkt->type);
574 if (!setup_compression(bctx)) {
578 if (bctx.ff_pkt->flags & FO_ENCRYPT && !crypto_allocate_ctx(bctx)) {
583 * Send Data header to Storage daemon
584 * <file-index> <stream> <expected stream length>
586 if (!sd->fsend("%ld %d %lld", jcr->JobFiles, stream,
587 (int64_t)bctx.ff_pkt->statp.st_size)) {
588 if (!jcr->is_job_canceled()) {
589 Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
594 Dmsg1(300, ">stored: datahdr %s\n", sd->msg);
597 * Make space at beginning of buffer for fileAddr because this
598 * same buffer will be used for writing if compression is off.
600 if ((bctx.ff_pkt->flags & FO_SPARSE) || (bctx.ff_pkt->flags & FO_OFFSETS)) {
601 bctx.rbuf += OFFSET_FADDR_SIZE;
602 bctx.rsize -= OFFSET_FADDR_SIZE;
603 #if defined(HAVE_FREEBSD_OS) || defined(__FreeBSD_kernel__)
605 * To read FreeBSD partitions, the read size must be
608 bctx.rsize = (bctx.rsize/512) * 512;
612 /** a RAW device read on win32 only works if the buffer is a multiple of 512 */
614 if (S_ISBLK(bctx.ff_pkt->statp.st_mode)) {
615 bctx.rsize = (bctx.rsize/512) * 512;
617 Dmsg1(200, "Fattrs=0X%x\n", bctx.ff_pkt->bfd.fattrs);
618 if (bctx.ff_pkt->bfd.fattrs & FILE_ATTRIBUTE_ENCRYPTED) {
619 if (!p_ReadEncryptedFileRaw) {
620 Jmsg0(bctx.jcr, M_FATAL, 0, _("Windows Encrypted data not supported on this OS.\n"));
623 /* This single call reads all EFS data delivers it to a callback */
624 if (p_ReadEncryptedFileRaw((PFE_EXPORT_FUNC)read_efs_data_cb, &bctx,
625 bctx.ff_pkt->bfd.pvContext) != 0) {
628 /* All read, so skip to finish sending */
631 /* Fall through to standard bread() loop */
635 * Normal read the file data in a loop and send it to SD
637 while ((sd->msglen=(uint32_t)bread(&bctx.ff_pkt->bfd, bctx.rbuf, bctx.rsize)) > 0) {
638 if (!process_and_send_data(bctx)) {
641 } /* end while read file data */
645 if (sd->msglen < 0) { /* error */
647 Jmsg(jcr, M_ERROR, 0, _("Read error on file %s. ERR=%s\n"),
648 bctx.ff_pkt->fname, be.bstrerror(bctx.ff_pkt->bfd.berrno));
649 if (jcr->JobErrors++ > 1000) { /* insanity check */
650 Jmsg(jcr, M_FATAL, 0, _("Too many errors. JobErrors=%d.\n"), jcr->JobErrors);
652 } else if (bctx.ff_pkt->flags & FO_ENCRYPT) {
654 * For encryption, we must call finalize to push out any
657 if (!crypto_cipher_finalize(bctx.cipher_ctx, (uint8_t *)jcr->crypto.crypto_buf,
658 &bctx.encrypted_len)) {
659 /* Padding failed. Shouldn't happen. */
660 Jmsg(jcr, M_FATAL, 0, _("Encryption padding error\n"));
664 /** Note, on SSL pre-0.9.7, there is always some output */
665 if (bctx.encrypted_len > 0) {
666 sd->msglen = bctx.encrypted_len; /* set encrypted length */
667 sd->msg = jcr->crypto.crypto_buf; /* set correct write buffer */
669 if (!jcr->is_job_canceled()) {
670 Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
675 Dmsg1(130, "Send data to SD len=%d\n", sd->msglen);
676 jcr->JobBytes += sd->msglen; /* count bytes saved possibly compressed/encrypted */
677 sd->msg = bctx.msgsave; /* restore bnet buffer */
682 if (!sd->signal(BNET_EOD)) { /* indicate end of file data */
683 if (!jcr->is_job_canceled()) {
684 Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
690 /** Free the cipher context */
691 if (bctx.cipher_ctx) {
692 crypto_cipher_free(bctx.cipher_ctx);
697 /** Free the cipher context */
698 if (bctx.cipher_ctx) {
699 crypto_cipher_free(bctx.cipher_ctx);
702 sd->msg = bctx.msgsave; /* restore bnet buffer */
709 * Apply processing (sparse, compression, encryption, and
712 bool process_and_send_data(bctx_t &bctx)
717 /** Check for sparse blocks */
718 if (bctx.ff_pkt->flags & FO_SPARSE) {
720 bool allZeros = false;
721 if ((sd->msglen == bctx.rsize &&
722 bctx.fileAddr+sd->msglen < (uint64_t)bctx.ff_pkt->statp.st_size) ||
723 ((bctx.ff_pkt->type == FT_RAW || bctx.ff_pkt->type == FT_FIFO) &&
724 (uint64_t)bctx.ff_pkt->statp.st_size == 0)) {
725 allZeros = is_buf_zero(bctx.rbuf, bctx.rsize);
728 /** Put file address as first data in buffer */
729 ser_begin(bctx.wbuf, OFFSET_FADDR_SIZE);
730 ser_uint64(bctx.fileAddr); /* store fileAddr in begin of buffer */
732 bctx.fileAddr += sd->msglen; /* update file address */
733 /** Skip block of all zeros */
735 return true; /* skip block of zeros */
737 } else if (bctx.ff_pkt->flags & FO_OFFSETS) {
739 ser_begin(bctx.wbuf, OFFSET_FADDR_SIZE);
740 ser_uint64(bctx.ff_pkt->bfd.offset); /* store offset in begin of buffer */
743 jcr->ReadBytes += sd->msglen; /* count bytes read */
745 /** Uncompressed cipher input length */
746 bctx.cipher_input_len = sd->msglen;
748 /** Update checksum if requested */
750 crypto_digest_update(bctx.digest, (uint8_t *)bctx.rbuf, sd->msglen);
753 /** Update signing digest if requested */
754 if (bctx.signing_digest) {
755 crypto_digest_update(bctx.signing_digest, (uint8_t *)bctx.rbuf, sd->msglen);
758 if (have_libz && !do_libz_compression(bctx)) {
762 if (have_lzo && !do_lzo_compression(bctx)) {
767 * Note, here we prepend the current record length to the beginning
768 * of the encrypted data. This is because both sparse and compression
769 * restore handling want records returned to them with exactly the
770 * same number of bytes that were processed in the backup handling.
771 * That is, both are block filters rather than a stream. When doing
772 * compression, the compression routines may buffer data, so that for
773 * any one record compressed, when it is decompressed the same size
774 * will not be obtained. Of course, the buffered data eventually comes
775 * out in subsequent crypto_cipher_update() calls or at least
776 * when crypto_cipher_finalize() is called. Unfortunately, this
777 * "feature" of encryption enormously complicates the restore code.
779 if (bctx.ff_pkt->flags & FO_ENCRYPT) {
780 uint32_t initial_len = 0;
783 if ((bctx.ff_pkt->flags & FO_SPARSE) || (bctx.ff_pkt->flags & FO_OFFSETS)) {
784 bctx.cipher_input_len += OFFSET_FADDR_SIZE;
787 /** Encrypt the length of the input block */
788 uint8_t packet_len[sizeof(uint32_t)];
790 ser_begin(packet_len, sizeof(uint32_t));
791 ser_uint32(bctx.cipher_input_len); /* store data len in begin of buffer */
792 Dmsg1(20, "Encrypt len=%d\n", bctx.cipher_input_len);
794 if (!crypto_cipher_update(bctx.cipher_ctx, packet_len, sizeof(packet_len),
795 (uint8_t *)jcr->crypto.crypto_buf, &initial_len)) {
796 /** Encryption failed. Shouldn't happen. */
797 Jmsg(jcr, M_FATAL, 0, _("Encryption error\n"));
801 /** Encrypt the input block */
802 if (crypto_cipher_update(bctx.cipher_ctx, bctx.cipher_input, bctx.cipher_input_len,
803 (uint8_t *)&jcr->crypto.crypto_buf[initial_len], &bctx.encrypted_len)) {
804 if ((initial_len + bctx.encrypted_len) == 0) {
805 /** No full block of data available, read more data */
808 Dmsg2(400, "encrypted len=%d unencrypted len=%d\n", bctx.encrypted_len,
810 sd->msglen = initial_len + bctx.encrypted_len; /* set encrypted length */
812 /** Encryption failed. Shouldn't happen. */
813 Jmsg(jcr, M_FATAL, 0, _("Encryption error\n"));
818 /* Send the buffer to the Storage daemon */
819 if ((bctx.ff_pkt->flags & FO_SPARSE) || (bctx.ff_pkt->flags & FO_OFFSETS)) {
820 sd->msglen += OFFSET_FADDR_SIZE; /* include fileAddr in size */
822 sd->msg = bctx.wbuf; /* set correct write buffer */
824 if (!jcr->is_job_canceled()) {
825 Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
830 Dmsg1(130, "Send data to SD len=%d\n", sd->msglen);
832 jcr->JobBytes += sd->msglen; /* count bytes saved possibly compressed/encrypted */
833 sd->msg = bctx.msgsave; /* restore read buffer */
840 bool encode_and_send_attributes(bctx_t &bctx)
842 BSOCK *sd = bctx.jcr->store_bsock;
844 FF_PKT *ff_pkt = bctx.ff_pkt;
845 char attribs[MAXSTRING];
846 char attribsExBuf[MAXSTRING];
847 char *attribsEx = NULL;
851 int hangup = get_hangup();
852 int blowup = get_blowup();
853 #ifdef FD_NO_SEND_TEST
857 Dmsg1(300, "encode_and_send_attrs fname=%s\n", ff_pkt->fname);
858 /** Find what data stream we will use, then encode the attributes */
859 if ((bctx.data_stream = select_data_stream(ff_pkt)) == STREAM_NONE) {
860 /* This should not happen */
861 Jmsg0(jcr, M_FATAL, 0, _("Invalid file flags, no supported data stream type.\n"));
864 encode_stat(attribs, &ff_pkt->statp, sizeof(ff_pkt->statp), ff_pkt->LinkFI, bctx.data_stream);
866 /** Now possibly extend the attributes */
867 if (IS_FT_OBJECT(ff_pkt->type)) {
868 attr_stream = STREAM_RESTORE_OBJECT;
870 attribsEx = attribsExBuf;
871 attr_stream = encode_attribsEx(jcr, attribsEx, ff_pkt);
874 Dmsg3(300, "File %s\nattribs=%s\nattribsEx=%s\n", ff_pkt->fname, attribs, attribsEx);
877 jcr->JobFiles++; /* increment number of files sent */
878 ff_pkt->FileIndex = jcr->JobFiles; /* return FileIndex */
879 pm_strcpy(jcr->last_fname, ff_pkt->fname);
882 /* Display the information about the current file if requested */
883 if (is_message_type_set(jcr, M_SAVED)) {
885 memcpy(&attr.statp, &ff_pkt->statp, sizeof(struct stat));
886 attr.type = ff_pkt->type;
887 attr.ofname = (POOLMEM *)ff_pkt->fname;
888 attr.olname = (POOLMEM *)ff_pkt->link;
889 print_ls_output(jcr, &attr, M_SAVED);
892 /* Debug code: check if we must hangup */
893 if (hangup > 0 && (jcr->JobFiles > (uint32_t)hangup)) {
894 jcr->setJobStatus(JS_Incomplete);
895 Jmsg1(jcr, M_FATAL, 0, "Debug hangup requested after %d files.\n", hangup);
900 if (blowup > 0 && (jcr->JobFiles > (uint32_t)blowup)) {
901 Jmsg1(jcr, M_ABORT, 0, "Debug blowup requested after %d files.\n", blowup);
906 * Send Attributes header to Storage daemon
907 * <file-index> <stream> <info>
909 if (!sd->fsend("%ld %d 0", jcr->JobFiles, attr_stream)) {
910 if (!jcr->is_canceled() && !jcr->is_incomplete()) {
911 Jmsg2(jcr, M_FATAL, 0, _("Network send error to SD. Data=%s ERR=%s\n"),
912 sd->msg, sd->bstrerror());
916 Dmsg1(300, ">stored: attrhdr %s\n", sd->msg);
919 * Send file attributes to Storage daemon
922 * Filename (full path)
924 * Link name (if type==FT_LNK or FT_LNKSAVED)
925 * Encoded extended-attributes (for Win32)
927 * or send Restore Object to Storage daemon
931 * Object_len (possibly compressed)
932 * Object_full_len (not compressed)
938 * For a directory, link is the same as fname, but with trailing
939 * slash. For a linked file, link is the link.
941 if (!IS_FT_OBJECT(ff_pkt->type) && ff_pkt->type != FT_DELETED) { /* already stripped */
944 switch (ff_pkt->type) {
947 Dmsg3(300, "Link %d %s to %s\n", jcr->JobFiles, ff_pkt->fname, ff_pkt->link);
948 stat = sd->fsend("%ld %d %s%c%s%c%s%c%s%c%u%c", jcr->JobFiles,
949 ff_pkt->type, ff_pkt->fname, 0, attribs, 0,
950 ff_pkt->link, 0, attribsEx, 0, ff_pkt->delta_seq, 0);
955 /* Here link is the canonical filename (i.e. with trailing slash) */
956 stat = sd->fsend("%ld %d %s%c%s%c%c%s%c%u%c", jcr->JobFiles,
957 ff_pkt->type, ff_pkt->link, 0, attribs, 0, 0,
958 attribsEx, 0, ff_pkt->delta_seq, 0);
960 case FT_PLUGIN_CONFIG:
961 case FT_RESTORE_FIRST:
962 comp_len = ff_pkt->object_len;
963 ff_pkt->object_compression = 0;
964 if (ff_pkt->object_len > 1000) {
965 /* Big object, compress it */
966 comp_len = ff_pkt->object_len + 1000;
967 POOLMEM *comp_obj = get_memory(comp_len);
968 /* *** FIXME *** check Zdeflate error */
969 Zdeflate(ff_pkt->object, ff_pkt->object_len, comp_obj, comp_len);
970 if (comp_len < ff_pkt->object_len) {
971 ff_pkt->object = comp_obj;
972 ff_pkt->object_compression = 1; /* zlib level 9 compression */
974 /* Uncompressed object smaller, use it */
975 comp_len = ff_pkt->object_len;
977 Dmsg2(100, "Object compressed from %d to %d bytes\n", ff_pkt->object_len, comp_len);
979 sd->msglen = Mmsg(sd->msg, "%d %d %d %d %d %d %s%c%s%c",
980 jcr->JobFiles, ff_pkt->type, ff_pkt->object_index,
981 comp_len, ff_pkt->object_len, ff_pkt->object_compression,
982 ff_pkt->fname, 0, ff_pkt->object_name, 0);
983 sd->msg = check_pool_memory_size(sd->msg, sd->msglen + comp_len + 2);
984 memcpy(sd->msg + sd->msglen, ff_pkt->object, comp_len);
985 /* Note we send one extra byte so Dir can store zero after object */
986 sd->msglen += comp_len + 1;
988 if (ff_pkt->object_compression) {
989 free_and_null_pool_memory(ff_pkt->object);
993 stat = sd->fsend("%ld %d %s%c%s%c%c%s%c%d%c", jcr->JobFiles,
994 ff_pkt->type, ff_pkt->fname, 0, attribs, 0, 0, attribsEx, 0,
995 ff_pkt->delta_seq, 0);
998 stat = sd->fsend("%ld %d %s%c%s%c%c%s%c%u%c", jcr->JobFiles,
999 ff_pkt->type, ff_pkt->fname, 0, attribs, 0, 0,
1000 attribsEx, 0, ff_pkt->delta_seq, 0);
1004 if (!IS_FT_OBJECT(ff_pkt->type) && ff_pkt->type != FT_DELETED) {
1005 unstrip_path(ff_pkt);
1008 Dmsg2(300, ">stored: attr len=%d: %s\n", sd->msglen, sd->msg);
1009 if (!stat && !jcr->is_job_canceled()) {
1010 Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
1013 sd->signal(BNET_EOD); /* indicate end of attributes data */
1018 * Setup bctx for doing compression
1020 static bool setup_compression(bctx_t &bctx)
1022 JCR *jcr = bctx.jcr;
1024 #if defined(HAVE_LIBZ) || defined(HAVE_LZO)
1025 bctx.compress_len = 0;
1026 bctx.max_compress_len = 0;
1031 if ((bctx.ff_pkt->flags & FO_COMPRESS) && bctx.ff_pkt->Compress_algo == COMPRESS_GZIP) {
1032 if ((bctx.ff_pkt->flags & FO_SPARSE) || (bctx.ff_pkt->flags & FO_OFFSETS)) {
1033 bctx.cbuf = (Bytef *)jcr->compress_buf + OFFSET_FADDR_SIZE;
1034 bctx.max_compress_len = jcr->compress_buf_size - OFFSET_FADDR_SIZE;
1036 bctx.cbuf = (Bytef *)jcr->compress_buf;
1037 bctx.max_compress_len = jcr->compress_buf_size; /* set max length */
1039 bctx.wbuf = jcr->compress_buf; /* compressed output here */
1040 bctx.cipher_input = (uint8_t *)jcr->compress_buf; /* encrypt compressed data */
1043 * Only change zlib parameters if there is no pending operation.
1044 * This should never happen as deflatereset is called after each
1048 if (((z_stream*)jcr->pZLIB_compress_workset)->total_in == 0) {
1049 /** set gzip compression level - must be done per file */
1050 if ((zstat=deflateParams((z_stream*)jcr->pZLIB_compress_workset,
1051 bctx.ff_pkt->Compress_level, Z_DEFAULT_STRATEGY)) != Z_OK) {
1052 Jmsg(jcr, M_FATAL, 0, _("Compression deflateParams error: %d\n"), zstat);
1053 jcr->setJobStatus(JS_ErrorTerminated);
1060 memset(&bctx.ch, 0, sizeof(comp_stream_header));
1063 if ((bctx.ff_pkt->flags & FO_COMPRESS) && bctx.ff_pkt->Compress_algo == COMPRESS_LZO1X) {
1064 if ((bctx.ff_pkt->flags & FO_SPARSE) || (bctx.ff_pkt->flags & FO_OFFSETS)) {
1065 bctx.cbuf = (Bytef *)jcr->compress_buf + OFFSET_FADDR_SIZE;
1066 bctx.cbuf2 = (Bytef *)jcr->compress_buf + OFFSET_FADDR_SIZE + sizeof(comp_stream_header);
1067 bctx.max_compress_len = jcr->compress_buf_size - OFFSET_FADDR_SIZE;
1069 bctx.cbuf = (Bytef *)jcr->compress_buf;
1070 bctx.cbuf2 = (Bytef *)jcr->compress_buf + sizeof(comp_stream_header);
1071 bctx.max_compress_len = jcr->compress_buf_size; /* set max length */
1073 bctx.ch.magic = COMPRESS_LZO1X;
1074 bctx.ch.version = COMP_HEAD_VERSION;
1075 bctx.wbuf = jcr->compress_buf; /* compressed output here */
1076 bctx.cipher_input = (uint8_t *)jcr->compress_buf; /* encrypt compressed data */
1080 bctx.max_compress_len = 0;
1086 * Send MacOS resource fork to SD
1088 #ifdef HAVE_DARWIN_OS
1089 static bool send_resource_fork(bctx_t &bctx)
1091 FF_PKT *ff_pkt = bctx.ff_pkt;
1092 JCR *jcr = bctx.jcr;
1093 BSOCK *sd = bctx.sd;
1096 /** Regular files can have resource forks and Finder Info */
1097 if (ff_pkt->type != FT_LNKSAVED && (S_ISREG(ff_pkt->statp.st_mode) &&
1098 ff_pkt->flags & FO_HFSPLUS)) {
1099 if (ff_pkt->hfsinfo.rsrclength > 0) {
1102 if (bopen_rsrc(&ff_pkt->bfd, ff_pkt->fname, O_RDONLY | O_BINARY, 0) < 0) {
1103 ff_pkt->ff_errno = errno;
1105 Jmsg(jcr, M_NOTSAVED, -1, _(" Cannot open resource fork for \"%s\": ERR=%s.\n"),
1106 ff_pkt->fname, be.bstrerror());
1108 if (is_bopen(&ff_pkt->bfd)) {
1109 bclose(&ff_pkt->bfd);
1113 flags = ff_pkt->flags;
1114 ff_pkt->flags &= ~(FO_COMPRESS|FO_SPARSE|FO_OFFSETS);
1115 if (flags & FO_ENCRYPT) {
1116 rsrc_stream = STREAM_ENCRYPTED_MACOS_FORK_DATA;
1118 rsrc_stream = STREAM_MACOS_FORK_DATA;
1120 stat = send_data(bctx, rsrc_stream);
1121 ff_pkt->flags = flags;
1122 bclose(&ff_pkt->bfd);
1128 Dmsg1(300, "Saving Finder Info for \"%s\"\n", ff_pkt->fname);
1129 sd->fsend("%ld %d 0", jcr->JobFiles, STREAM_HFSPLUS_ATTRIBUTES);
1130 Dmsg1(300, "bfiled>stored:header %s\n", sd->msg);
1131 pm_memcpy(sd->msg, ff_pkt->hfsinfo.fndrinfo, 32);
1134 crypto_digest_update(bctx.digest, (uint8_t *)sd->msg, sd->msglen);
1136 if (bctx.signing_digest) {
1137 crypto_digest_update(bctx.signing_digest, (uint8_t *)sd->msg, sd->msglen);
1140 sd->signal(BNET_EOD);
1146 static bool do_libz_compression(bctx_t &bctx)
1149 JCR *jcr = bctx.jcr;
1150 BSOCK *sd = bctx.sd;
1153 /** Do compression if turned on */
1154 if (bctx.ff_pkt->flags & FO_COMPRESS && bctx.ff_pkt->Compress_algo == COMPRESS_GZIP && jcr->pZLIB_compress_workset) {
1155 Dmsg3(400, "cbuf=0x%x rbuf=0x%x len=%u\n", bctx.cbuf, bctx.rbuf, sd->msglen);
1157 ((z_stream*)jcr->pZLIB_compress_workset)->next_in = (Bytef *)bctx.rbuf;
1158 ((z_stream*)jcr->pZLIB_compress_workset)->avail_in = sd->msglen;
1159 ((z_stream*)jcr->pZLIB_compress_workset)->next_out = bctx.cbuf;
1160 ((z_stream*)jcr->pZLIB_compress_workset)->avail_out = bctx.max_compress_len;
1162 if ((zstat=deflate((z_stream*)jcr->pZLIB_compress_workset, Z_FINISH)) != Z_STREAM_END) {
1163 Jmsg(jcr, M_FATAL, 0, _("Compression deflate error: %d\n"), zstat);
1164 jcr->setJobStatus(JS_ErrorTerminated);
1167 bctx.compress_len = ((z_stream*)jcr->pZLIB_compress_workset)->total_out;
1168 /** reset zlib stream to be able to begin from scratch again */
1169 if ((zstat=deflateReset((z_stream*)jcr->pZLIB_compress_workset)) != Z_OK) {
1170 Jmsg(jcr, M_FATAL, 0, _("Compression deflateReset error: %d\n"), zstat);
1171 jcr->setJobStatus(JS_ErrorTerminated);
1175 Dmsg2(400, "GZIP compressed len=%d uncompressed len=%d\n", bctx.compress_len,
1178 sd->msglen = bctx.compress_len; /* set compressed length */
1179 bctx.cipher_input_len = bctx.compress_len;
1185 static bool do_lzo_compression(bctx_t &bctx)
1188 JCR *jcr = bctx.jcr;
1189 BSOCK *sd = bctx.sd;
1192 /** Do compression if turned on */
1193 if (bctx.ff_pkt->flags & FO_COMPRESS && bctx.ff_pkt->Compress_algo == COMPRESS_LZO1X && jcr->LZO_compress_workset) {
1194 lzo_uint len; /* TODO: See with the latest patch how to handle lzo_uint with 64bit */
1197 ser_begin(bctx.cbuf, sizeof(comp_stream_header));
1199 Dmsg3(400, "cbuf=0x%x rbuf=0x%x len=%u\n", bctx.cbuf, bctx.rbuf, sd->msglen);
1201 lzores = lzo1x_1_compress((const unsigned char*)bctx.rbuf, sd->msglen, bctx.cbuf2,
1202 &len, jcr->LZO_compress_workset);
1203 bctx.compress_len = len;
1204 if (lzores == LZO_E_OK && bctx.compress_len <= bctx.max_compress_len) {
1205 /* complete header */
1206 ser_uint32(COMPRESS_LZO1X);
1207 ser_uint32(bctx.compress_len);
1208 ser_uint16(bctx.ch.level);
1209 ser_uint16(bctx.ch.version);
1211 /** this should NEVER happen */
1212 Jmsg(jcr, M_FATAL, 0, _("Compression LZO error: %d\n"), lzores);
1213 jcr->setJobStatus(JS_ErrorTerminated);
1217 Dmsg2(400, "LZO compressed len=%d uncompressed len=%d\n", bctx.compress_len,
1220 bctx.compress_len += sizeof(comp_stream_header); /* add size of header */
1221 sd->msglen = bctx.compress_len; /* set compressed length */
1222 bctx.cipher_input_len = bctx.compress_len;
1229 * Do in place strip of path
1231 static bool do_snap_strip(FF_PKT *ff)
1233 /* if the string starts with the snapshot path name, we can replace
1234 * by the volume name. The volume_path is smaller than the snapshot_path
1235 * snapshot_path = volume_path + /.snapshots/job-xxxx
1237 ASSERT(strlen(ff->snapshot_path) > strlen(ff->volume_path));
1238 int sp_first = strlen(ff->snapshot_path); /* point after snapshot_path in fname */
1239 if (strncmp(ff->fname, ff->snapshot_path, sp_first) == 0) {
1240 int last = pm_strcpy(ff->snap_fname, ff->volume_path);
1241 last = MAX(last - 1, 0);
1243 if (ff->snap_fname[last] == '/') {
1244 if (ff->fname[sp_first] == '/') { /* compare with the first character of the string (sp_first not sp_first-1) */
1245 ff->snap_fname[last] = 0;
1248 if (ff->fname[sp_first] != '/') {
1249 pm_strcat(ff->snap_fname, "/");
1253 pm_strcat(ff->snap_fname, ff->fname + sp_first);
1254 ASSERT(strlen(ff->fname) > strlen(ff->snap_fname));
1255 strcpy(ff->fname, ff->snap_fname);
1256 Dmsg2(DT_SNAPSHOT|20, "%s -> %s\n", ff->fname_save, ff->fname);
1258 if (strncmp(ff->link, ff->snapshot_path, sp_first) == 0) {
1259 int last = pm_strcpy(ff->snap_fname, ff->volume_path);
1260 last = MAX(last - 1, 0);
1262 if (ff->snap_fname[last] == '/') {
1263 if (ff->link[sp_first] == '/') { /* compare with the first character of the string (sp_first not sp_first-1) */
1264 ff->snap_fname[last] = 0;
1267 if (ff->link[sp_first] != '/') {
1268 pm_strcat(ff->snap_fname, "/");
1272 pm_strcat(ff->snap_fname, ff->link + sp_first);
1273 ASSERT(strlen(ff->link) > strlen(ff->snap_fname));
1274 strcpy(ff->link, ff->snap_fname);
1275 Dmsg2(DT_SNAPSHOT|20, "%s -> %s\n", ff->link_save, ff->link);
1282 * Do in place strip of path
1284 static bool do_strip(int count, char *in)
1290 /** Copy to first path separator -- Win32 might have c: ... */
1291 while (*in && !IsPathSeparator(*in)) {
1294 if (*in) { /* Not at the end of the string */
1296 numsep++; /* one separator seen */
1298 for (stripped=0; stripped<count && *in; stripped++) {
1299 while (*in && !IsPathSeparator(*in)) {
1300 in++; /* skip chars */
1303 numsep++; /* count separators seen */
1304 in++; /* skip separator */
1308 while (*in) { /* copy to end */
1309 if (IsPathSeparator(*in)) {
1315 Dmsg4(500, "stripped=%d count=%d numsep=%d sep>count=%d\n",
1316 stripped, count, numsep, numsep>count);
1317 return stripped==count && numsep>count;
1321 * If requested strip leading components of the path so that we can
1322 * save file as if it came from a subdirectory. This is most useful
1323 * for dealing with snapshots, by removing the snapshot directory, or
1324 * in handling vendor migrations where files have been restored with
1325 * a vendor product into a subdirectory.
1327 * When we are using snapshots, we might need to convert the path
1328 * back to the original one using the strip_snap_path option.
1330 void strip_path(FF_PKT *ff_pkt)
1332 if (!ff_pkt->strip_snap_path &&
1333 (!(ff_pkt->flags & FO_STRIPPATH) || ff_pkt->strip_path <= 0))
1335 Dmsg1(200, "No strip for %s\n", ff_pkt->fname);
1338 /* shared part between strip and snapshot */
1339 if (!ff_pkt->fname_save) {
1340 ff_pkt->fname_save = get_pool_memory(PM_FNAME);
1341 ff_pkt->link_save = get_pool_memory(PM_FNAME);
1342 *ff_pkt->link_save = 0;
1344 pm_strcpy(ff_pkt->fname_save, ff_pkt->fname);
1345 if (ff_pkt->type != FT_LNK && ff_pkt->fname != ff_pkt->link) {
1346 pm_strcpy(ff_pkt->link_save, ff_pkt->link);
1347 Dmsg2(500, "strcpy link_save=%d link=%d\n", strlen(ff_pkt->link_save),
1348 strlen(ff_pkt->link));
1352 if (ff_pkt->strip_snap_path) {
1353 if (!do_snap_strip(ff_pkt)) {
1354 Dmsg1(0, "Something wrong with do_snap_strip(%s)\n", ff_pkt->fname);
1355 unstrip_path(ff_pkt);
1360 /* See if we want also to strip the path */
1361 if (!(ff_pkt->flags & FO_STRIPPATH) || ff_pkt->strip_path <= 0) {
1366 * Strip path. If it doesn't succeed put it back. If
1367 * it does, and there is a different link string,
1368 * attempt to strip the link. If it fails, back them
1370 * Do not strip symlinks.
1371 * I.e. if either stripping fails don't strip anything.
1373 if (!do_strip(ff_pkt->strip_path, ff_pkt->fname)) {
1374 unstrip_path(ff_pkt);
1377 /** Strip links but not symlinks */
1378 if (ff_pkt->type != FT_LNK && ff_pkt->fname != ff_pkt->link) {
1379 if (!do_strip(ff_pkt->strip_path, ff_pkt->link)) {
1380 unstrip_path(ff_pkt);
1385 Dmsg3(10, "fname=%s stripped=%s link=%s\n", ff_pkt->fname_save, ff_pkt->fname,
1389 void unstrip_path(FF_PKT *ff_pkt)
1391 if (!ff_pkt->strip_snap_path &&
1392 (!(ff_pkt->flags & FO_STRIPPATH) || ff_pkt->strip_path <= 0))
1397 strcpy(ff_pkt->fname, ff_pkt->fname_save);
1398 if (ff_pkt->type != FT_LNK && ff_pkt->fname != ff_pkt->link) {
1399 Dmsg2(10, "strcpy link=%s link_save=%s\n", ff_pkt->link,
1401 strcpy(ff_pkt->link, ff_pkt->link_save);
1402 Dmsg2(10, "strcpy link=%d link_save=%d\n", strlen(ff_pkt->link),
1403 strlen(ff_pkt->link_save));
1408 static void close_vss_backup_session(JCR *jcr)
1410 #if defined(WIN32_VSS)
1411 /* STOP VSS ON WIN32 */
1412 /* tell vss to close the backup session */
1413 if (jcr->Snapshot) {
1414 if (g_pVSSClient->CloseBackup()) {
1415 /* inform user about writer states */
1416 for (int i=0; i<(int)g_pVSSClient->GetWriterCount(); i++) {
1417 int msg_type = M_INFO;
1418 if (g_pVSSClient->GetWriterState(i) < 1) {
1419 msg_type = M_WARNING;
1422 Jmsg(jcr, msg_type, 0, _("VSS Writer (BackupComplete): %s\n"), g_pVSSClient->GetWriterInfo(i));
1425 /* Generate Job global writer metadata */
1426 WCHAR *metadata = g_pVSSClient->GetMetadata();
1428 FF_PKT *ff_pkt = jcr->ff;
1429 ff_pkt->fname = (char *)"*all*"; /* for all plugins */
1430 ff_pkt->type = FT_RESTORE_FIRST;
1432 ff_pkt->object_name = (char *)"job_metadata.xml";
1433 ff_pkt->object = (char *)metadata;
1434 ff_pkt->object_len = (wcslen(metadata) + 1) * sizeof(WCHAR);
1435 ff_pkt->object_index = (int)time(NULL);
1436 save_file(jcr, ff_pkt, true);