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 Job=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 /* Debug code: check if we must hangup */
883 if (hangup > 0 && (jcr->JobFiles > (uint32_t)hangup)) {
884 jcr->setJobStatus(JS_Incomplete);
885 Jmsg1(jcr, M_FATAL, 0, "Debug hangup requested after %d files.\n", hangup);
890 if (blowup > 0 && (jcr->JobFiles > (uint32_t)blowup)) {
891 Jmsg1(jcr, M_ABORT, 0, "Debug blowup requested after %d files.\n", blowup);
896 * Send Attributes header to Storage daemon
897 * <file-index> <stream> <info>
899 if (!sd->fsend("%ld %d 0", jcr->JobFiles, attr_stream)) {
900 if (!jcr->is_canceled() && !jcr->is_incomplete()) {
901 Jmsg2(jcr, M_FATAL, 0, _("Network send error to SD. Data=%s ERR=%s\n"),
902 sd->msg, sd->bstrerror());
906 Dmsg1(300, ">stored: attrhdr %s\n", sd->msg);
909 * Send file attributes to Storage daemon
912 * Filename (full path)
914 * Link name (if type==FT_LNK or FT_LNKSAVED)
915 * Encoded extended-attributes (for Win32)
917 * or send Restore Object to Storage daemon
921 * Object_len (possibly compressed)
922 * Object_full_len (not compressed)
928 * For a directory, link is the same as fname, but with trailing
929 * slash. For a linked file, link is the link.
931 if (!IS_FT_OBJECT(ff_pkt->type) && ff_pkt->type != FT_DELETED) { /* already stripped */
934 switch (ff_pkt->type) {
937 Dmsg3(300, "Link %d %s to %s\n", jcr->JobFiles, ff_pkt->fname, ff_pkt->link);
938 stat = sd->fsend("%ld %d %s%c%s%c%s%c%s%c%u%c", jcr->JobFiles,
939 ff_pkt->type, ff_pkt->fname, 0, attribs, 0,
940 ff_pkt->link, 0, attribsEx, 0, ff_pkt->delta_seq, 0);
945 /* Here link is the canonical filename (i.e. with trailing slash) */
946 stat = sd->fsend("%ld %d %s%c%s%c%c%s%c%u%c", jcr->JobFiles,
947 ff_pkt->type, ff_pkt->link, 0, attribs, 0, 0,
948 attribsEx, 0, ff_pkt->delta_seq, 0);
950 case FT_PLUGIN_CONFIG:
951 case FT_RESTORE_FIRST:
952 comp_len = ff_pkt->object_len;
953 ff_pkt->object_compression = 0;
954 if (ff_pkt->object_len > 1000) {
955 /* Big object, compress it */
956 comp_len = ff_pkt->object_len + 1000;
957 POOLMEM *comp_obj = get_memory(comp_len);
958 /* *** FIXME *** check Zdeflate error */
959 Zdeflate(ff_pkt->object, ff_pkt->object_len, comp_obj, comp_len);
960 if (comp_len < ff_pkt->object_len) {
961 ff_pkt->object = comp_obj;
962 ff_pkt->object_compression = 1; /* zlib level 9 compression */
964 /* Uncompressed object smaller, use it */
965 comp_len = ff_pkt->object_len;
967 Dmsg2(100, "Object compressed from %d to %d bytes\n", ff_pkt->object_len, comp_len);
969 sd->msglen = Mmsg(sd->msg, "%d %d %d %d %d %d %s%c%s%c",
970 jcr->JobFiles, ff_pkt->type, ff_pkt->object_index,
971 comp_len, ff_pkt->object_len, ff_pkt->object_compression,
972 ff_pkt->fname, 0, ff_pkt->object_name, 0);
973 sd->msg = check_pool_memory_size(sd->msg, sd->msglen + comp_len + 2);
974 memcpy(sd->msg + sd->msglen, ff_pkt->object, comp_len);
975 /* Note we send one extra byte so Dir can store zero after object */
976 sd->msglen += comp_len + 1;
978 if (ff_pkt->object_compression) {
979 free_and_null_pool_memory(ff_pkt->object);
983 stat = sd->fsend("%ld %d %s%c%s%c%c%s%c%d%c", jcr->JobFiles,
984 ff_pkt->type, ff_pkt->fname, 0, attribs, 0, 0, attribsEx, 0,
985 ff_pkt->delta_seq, 0);
988 stat = sd->fsend("%ld %d %s%c%s%c%c%s%c%u%c", jcr->JobFiles,
989 ff_pkt->type, ff_pkt->fname, 0, attribs, 0, 0,
990 attribsEx, 0, ff_pkt->delta_seq, 0);
994 if (!IS_FT_OBJECT(ff_pkt->type) && ff_pkt->type != FT_DELETED) {
995 unstrip_path(ff_pkt);
998 Dmsg2(300, ">stored: attr len=%d: %s\n", sd->msglen, sd->msg);
999 if (!stat && !jcr->is_job_canceled()) {
1000 Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
1003 sd->signal(BNET_EOD); /* indicate end of attributes data */
1008 * Setup bctx for doing compression
1010 static bool setup_compression(bctx_t &bctx)
1012 JCR *jcr = bctx.jcr;
1014 #if defined(HAVE_LIBZ) || defined(HAVE_LZO)
1015 bctx.compress_len = 0;
1016 bctx.max_compress_len = 0;
1021 if ((bctx.ff_pkt->flags & FO_COMPRESS) && bctx.ff_pkt->Compress_algo == COMPRESS_GZIP) {
1022 if ((bctx.ff_pkt->flags & FO_SPARSE) || (bctx.ff_pkt->flags & FO_OFFSETS)) {
1023 bctx.cbuf = (Bytef *)jcr->compress_buf + OFFSET_FADDR_SIZE;
1024 bctx.max_compress_len = jcr->compress_buf_size - OFFSET_FADDR_SIZE;
1026 bctx.cbuf = (Bytef *)jcr->compress_buf;
1027 bctx.max_compress_len = jcr->compress_buf_size; /* set max length */
1029 bctx.wbuf = jcr->compress_buf; /* compressed output here */
1030 bctx.cipher_input = (uint8_t *)jcr->compress_buf; /* encrypt compressed data */
1033 * Only change zlib parameters if there is no pending operation.
1034 * This should never happen as deflatereset is called after each
1038 if (((z_stream*)jcr->pZLIB_compress_workset)->total_in == 0) {
1039 /** set gzip compression level - must be done per file */
1040 if ((zstat=deflateParams((z_stream*)jcr->pZLIB_compress_workset,
1041 bctx.ff_pkt->Compress_level, Z_DEFAULT_STRATEGY)) != Z_OK) {
1042 Jmsg(jcr, M_FATAL, 0, _("Compression deflateParams error: %d\n"), zstat);
1043 jcr->setJobStatus(JS_ErrorTerminated);
1050 memset(&bctx.ch, 0, sizeof(comp_stream_header));
1053 if ((bctx.ff_pkt->flags & FO_COMPRESS) && bctx.ff_pkt->Compress_algo == COMPRESS_LZO1X) {
1054 if ((bctx.ff_pkt->flags & FO_SPARSE) || (bctx.ff_pkt->flags & FO_OFFSETS)) {
1055 bctx.cbuf = (Bytef *)jcr->compress_buf + OFFSET_FADDR_SIZE;
1056 bctx.cbuf2 = (Bytef *)jcr->compress_buf + OFFSET_FADDR_SIZE + sizeof(comp_stream_header);
1057 bctx.max_compress_len = jcr->compress_buf_size - OFFSET_FADDR_SIZE;
1059 bctx.cbuf = (Bytef *)jcr->compress_buf;
1060 bctx.cbuf2 = (Bytef *)jcr->compress_buf + sizeof(comp_stream_header);
1061 bctx.max_compress_len = jcr->compress_buf_size; /* set max length */
1063 bctx.ch.magic = COMPRESS_LZO1X;
1064 bctx.ch.version = COMP_HEAD_VERSION;
1065 bctx.wbuf = jcr->compress_buf; /* compressed output here */
1066 bctx.cipher_input = (uint8_t *)jcr->compress_buf; /* encrypt compressed data */
1070 bctx.max_compress_len = 0;
1076 * Send MacOS resource fork to SD
1078 #ifdef HAVE_DARWIN_OS
1079 static bool send_resource_fork(bctx_t &bctx)
1081 FF_PKT *ff_pkt = bctx.ff_pkt;
1082 JCR *jcr = bctx.jcr;
1083 BSOCK *sd = bctx.sd;
1086 /** Regular files can have resource forks and Finder Info */
1087 if (ff_pkt->type != FT_LNKSAVED && (S_ISREG(ff_pkt->statp.st_mode) &&
1088 ff_pkt->flags & FO_HFSPLUS)) {
1089 if (ff_pkt->hfsinfo.rsrclength > 0) {
1092 if (bopen_rsrc(&ff_pkt->bfd, ff_pkt->fname, O_RDONLY | O_BINARY, 0) < 0) {
1093 ff_pkt->ff_errno = errno;
1095 Jmsg(jcr, M_NOTSAVED, -1, _(" Cannot open resource fork for \"%s\": ERR=%s.\n"),
1096 ff_pkt->fname, be.bstrerror());
1098 if (is_bopen(&ff_pkt->bfd)) {
1099 bclose(&ff_pkt->bfd);
1103 flags = ff_pkt->flags;
1104 ff_pkt->flags &= ~(FO_COMPRESS|FO_SPARSE|FO_OFFSETS);
1105 if (flags & FO_ENCRYPT) {
1106 rsrc_stream = STREAM_ENCRYPTED_MACOS_FORK_DATA;
1108 rsrc_stream = STREAM_MACOS_FORK_DATA;
1110 stat = send_data(bctx, rsrc_stream);
1111 ff_pkt->flags = flags;
1112 bclose(&ff_pkt->bfd);
1118 Dmsg1(300, "Saving Finder Info for \"%s\"\n", ff_pkt->fname);
1119 sd->fsend("%ld %d 0", jcr->JobFiles, STREAM_HFSPLUS_ATTRIBUTES);
1120 Dmsg1(300, "bfiled>stored:header %s\n", sd->msg);
1121 pm_memcpy(sd->msg, ff_pkt->hfsinfo.fndrinfo, 32);
1124 crypto_digest_update(bctx.digest, (uint8_t *)sd->msg, sd->msglen);
1126 if (bctx.signing_digest) {
1127 crypto_digest_update(bctx.signing_digest, (uint8_t *)sd->msg, sd->msglen);
1130 sd->signal(BNET_EOD);
1136 static bool do_libz_compression(bctx_t &bctx)
1139 JCR *jcr = bctx.jcr;
1140 BSOCK *sd = bctx.sd;
1143 /** Do compression if turned on */
1144 if (bctx.ff_pkt->flags & FO_COMPRESS && bctx.ff_pkt->Compress_algo == COMPRESS_GZIP && jcr->pZLIB_compress_workset) {
1145 Dmsg3(400, "cbuf=0x%x rbuf=0x%x len=%u\n", bctx.cbuf, bctx.rbuf, sd->msglen);
1147 ((z_stream*)jcr->pZLIB_compress_workset)->next_in = (Bytef *)bctx.rbuf;
1148 ((z_stream*)jcr->pZLIB_compress_workset)->avail_in = sd->msglen;
1149 ((z_stream*)jcr->pZLIB_compress_workset)->next_out = bctx.cbuf;
1150 ((z_stream*)jcr->pZLIB_compress_workset)->avail_out = bctx.max_compress_len;
1152 if ((zstat=deflate((z_stream*)jcr->pZLIB_compress_workset, Z_FINISH)) != Z_STREAM_END) {
1153 Jmsg(jcr, M_FATAL, 0, _("Compression deflate error: %d\n"), zstat);
1154 jcr->setJobStatus(JS_ErrorTerminated);
1157 bctx.compress_len = ((z_stream*)jcr->pZLIB_compress_workset)->total_out;
1158 /** reset zlib stream to be able to begin from scratch again */
1159 if ((zstat=deflateReset((z_stream*)jcr->pZLIB_compress_workset)) != Z_OK) {
1160 Jmsg(jcr, M_FATAL, 0, _("Compression deflateReset error: %d\n"), zstat);
1161 jcr->setJobStatus(JS_ErrorTerminated);
1165 Dmsg2(400, "GZIP compressed len=%d uncompressed len=%d\n", bctx.compress_len,
1168 sd->msglen = bctx.compress_len; /* set compressed length */
1169 bctx.cipher_input_len = bctx.compress_len;
1175 static bool do_lzo_compression(bctx_t &bctx)
1178 JCR *jcr = bctx.jcr;
1179 BSOCK *sd = bctx.sd;
1182 /** Do compression if turned on */
1183 if (bctx.ff_pkt->flags & FO_COMPRESS && bctx.ff_pkt->Compress_algo == COMPRESS_LZO1X && jcr->LZO_compress_workset) {
1184 lzo_uint len; /* TODO: See with the latest patch how to handle lzo_uint with 64bit */
1187 ser_begin(bctx.cbuf, sizeof(comp_stream_header));
1189 Dmsg3(400, "cbuf=0x%x rbuf=0x%x len=%u\n", bctx.cbuf, bctx.rbuf, sd->msglen);
1191 lzores = lzo1x_1_compress((const unsigned char*)bctx.rbuf, sd->msglen, bctx.cbuf2,
1192 &len, jcr->LZO_compress_workset);
1193 bctx.compress_len = len;
1194 if (lzores == LZO_E_OK && bctx.compress_len <= bctx.max_compress_len) {
1195 /* complete header */
1196 ser_uint32(COMPRESS_LZO1X);
1197 ser_uint32(bctx.compress_len);
1198 ser_uint16(bctx.ch.level);
1199 ser_uint16(bctx.ch.version);
1201 /** this should NEVER happen */
1202 Jmsg(jcr, M_FATAL, 0, _("Compression LZO error: %d\n"), lzores);
1203 jcr->setJobStatus(JS_ErrorTerminated);
1207 Dmsg2(400, "LZO compressed len=%d uncompressed len=%d\n", bctx.compress_len,
1210 bctx.compress_len += sizeof(comp_stream_header); /* add size of header */
1211 sd->msglen = bctx.compress_len; /* set compressed length */
1212 bctx.cipher_input_len = bctx.compress_len;
1219 * Do in place strip of path
1221 static bool do_snap_strip(FF_PKT *ff)
1223 /* if the string starts with the snapshot path name, we can replace
1224 * by the volume name. The volume_path is smaller than the snapshot_path
1225 * snapshot_path = volume_path + /.snapshots/job-xxxx
1227 ASSERT(strlen(ff->snapshot_path) > strlen(ff->volume_path));
1228 int sp_first = strlen(ff->snapshot_path); /* point after snapshot_path in fname */
1229 if (strncmp(ff->fname, ff->snapshot_path, sp_first) == 0) {
1230 int last = pm_strcpy(ff->snap_fname, ff->volume_path);
1231 last = MAX(last - 1, 0);
1233 if (ff->snap_fname[last] == '/') {
1234 if (ff->fname[sp_first] == '/') { /* compare with the first character of the string (sp_first not sp_first-1) */
1235 ff->snap_fname[last] = 0;
1238 if (ff->fname[sp_first] != '/') {
1239 pm_strcat(ff->snap_fname, "/");
1243 pm_strcat(ff->snap_fname, ff->fname + sp_first);
1244 ASSERT(strlen(ff->fname) > strlen(ff->snap_fname));
1245 strcpy(ff->fname, ff->snap_fname);
1246 Dmsg2(DT_SNAPSHOT|20, "%s -> %s\n", ff->fname_save, ff->fname);
1248 if (strncmp(ff->link, ff->snapshot_path, sp_first) == 0) {
1249 int last = pm_strcpy(ff->snap_fname, ff->volume_path);
1250 last = MAX(last - 1, 0);
1252 if (ff->snap_fname[last] == '/') {
1253 if (ff->link[sp_first] == '/') { /* compare with the first character of the string (sp_first not sp_first-1) */
1254 ff->snap_fname[last] = 0;
1257 if (ff->link[sp_first] != '/') {
1258 pm_strcat(ff->snap_fname, "/");
1262 pm_strcat(ff->snap_fname, ff->link + sp_first);
1263 ASSERT(strlen(ff->link) > strlen(ff->snap_fname));
1264 strcpy(ff->link, ff->snap_fname);
1265 Dmsg2(DT_SNAPSHOT|20, "%s -> %s\n", ff->link_save, ff->link);
1272 * Do in place strip of path
1274 static bool do_strip(int count, char *in)
1280 /** Copy to first path separator -- Win32 might have c: ... */
1281 while (*in && !IsPathSeparator(*in)) {
1284 if (*in) { /* Not at the end of the string */
1286 numsep++; /* one separator seen */
1288 for (stripped=0; stripped<count && *in; stripped++) {
1289 while (*in && !IsPathSeparator(*in)) {
1290 in++; /* skip chars */
1293 numsep++; /* count separators seen */
1294 in++; /* skip separator */
1298 while (*in) { /* copy to end */
1299 if (IsPathSeparator(*in)) {
1305 Dmsg4(500, "stripped=%d count=%d numsep=%d sep>count=%d\n",
1306 stripped, count, numsep, numsep>count);
1307 return stripped==count && numsep>count;
1311 * If requested strip leading components of the path so that we can
1312 * save file as if it came from a subdirectory. This is most useful
1313 * for dealing with snapshots, by removing the snapshot directory, or
1314 * in handling vendor migrations where files have been restored with
1315 * a vendor product into a subdirectory.
1317 * When we are using snapshots, we might need to convert the path
1318 * back to the original one using the strip_snap_path option.
1320 void strip_path(FF_PKT *ff_pkt)
1322 if (!ff_pkt->strip_snap_path &&
1323 (!(ff_pkt->flags & FO_STRIPPATH) || ff_pkt->strip_path <= 0))
1325 Dmsg1(200, "No strip for %s\n", ff_pkt->fname);
1328 /* shared part between strip and snapshot */
1329 if (!ff_pkt->fname_save) {
1330 ff_pkt->fname_save = get_pool_memory(PM_FNAME);
1331 ff_pkt->link_save = get_pool_memory(PM_FNAME);
1332 *ff_pkt->link_save = 0;
1334 pm_strcpy(ff_pkt->fname_save, ff_pkt->fname);
1335 if (ff_pkt->type != FT_LNK && ff_pkt->fname != ff_pkt->link) {
1336 pm_strcpy(ff_pkt->link_save, ff_pkt->link);
1337 Dmsg2(500, "strcpy link_save=%d link=%d\n", strlen(ff_pkt->link_save),
1338 strlen(ff_pkt->link));
1342 if (ff_pkt->strip_snap_path) {
1343 if (!do_snap_strip(ff_pkt)) {
1344 Dmsg1(0, "Something wrong with do_snap_strip(%s)\n", ff_pkt->fname);
1345 unstrip_path(ff_pkt);
1350 /* See if we want also to strip the path */
1351 if (!(ff_pkt->flags & FO_STRIPPATH) || ff_pkt->strip_path <= 0) {
1356 * Strip path. If it doesn't succeed put it back. If
1357 * it does, and there is a different link string,
1358 * attempt to strip the link. If it fails, back them
1360 * Do not strip symlinks.
1361 * I.e. if either stripping fails don't strip anything.
1363 if (!do_strip(ff_pkt->strip_path, ff_pkt->fname)) {
1364 unstrip_path(ff_pkt);
1367 /** Strip links but not symlinks */
1368 if (ff_pkt->type != FT_LNK && ff_pkt->fname != ff_pkt->link) {
1369 if (!do_strip(ff_pkt->strip_path, ff_pkt->link)) {
1370 unstrip_path(ff_pkt);
1375 Dmsg3(10, "fname=%s stripped=%s link=%s\n", ff_pkt->fname_save, ff_pkt->fname,
1379 void unstrip_path(FF_PKT *ff_pkt)
1381 if (!ff_pkt->strip_snap_path &&
1382 (!(ff_pkt->flags & FO_STRIPPATH) || ff_pkt->strip_path <= 0))
1387 strcpy(ff_pkt->fname, ff_pkt->fname_save);
1388 if (ff_pkt->type != FT_LNK && ff_pkt->fname != ff_pkt->link) {
1389 Dmsg2(10, "strcpy link=%s link_save=%s\n", ff_pkt->link,
1391 strcpy(ff_pkt->link, ff_pkt->link_save);
1392 Dmsg2(10, "strcpy link=%d link_save=%d\n", strlen(ff_pkt->link),
1393 strlen(ff_pkt->link_save));
1398 static void close_vss_backup_session(JCR *jcr)
1400 #if defined(WIN32_VSS)
1401 /* STOP VSS ON WIN32 */
1402 /* tell vss to close the backup session */
1403 if (jcr->Snapshot) {
1404 if (g_pVSSClient->CloseBackup()) {
1405 /* inform user about writer states */
1406 for (int i=0; i<(int)g_pVSSClient->GetWriterCount(); i++) {
1407 int msg_type = M_INFO;
1408 if (g_pVSSClient->GetWriterState(i) < 1) {
1409 msg_type = M_WARNING;
1412 Jmsg(jcr, msg_type, 0, _("VSS Writer (BackupComplete): %s\n"), g_pVSSClient->GetWriterInfo(i));
1415 /* Generate Job global writer metadata */
1416 WCHAR *metadata = g_pVSSClient->GetMetadata();
1418 FF_PKT *ff_pkt = jcr->ff;
1419 ff_pkt->fname = (char *)"*all*"; /* for all plugins */
1420 ff_pkt->type = FT_RESTORE_FIRST;
1422 ff_pkt->object_name = (char *)"job_metadata.xml";
1423 ff_pkt->object = (char *)metadata;
1424 ff_pkt->object_len = (wcslen(metadata) + 1) * sizeof(WCHAR);
1425 ff_pkt->object_index = (int)time(NULL);
1426 save_file(jcr, ff_pkt, true);