2 Bacula(R) - The Network Backup Solution
4 Copyright (C) 2000-2015 Kern Sibbald
5 Copyright (C) 2000-2014 Free Software Foundation Europe e.V.
7 The original author of Bacula is Kern Sibbald, with contributions
8 from many others, a complete list can be found in the file AUTHORS.
10 You may use this file and others of this release according to the
11 license defined in the LICENSE file, which includes the Affero General
12 Public License, v3.0 ("AGPLv3") and some additional permissions and
13 terms pursuant to its AGPLv3 Section 7.
15 This notice must be preserved when any source code is
16 conveyed and/or propagated.
18 Bacula(R) is a registered trademark of Kern Sibbald.
21 * Bacula File Daemon backup.c send file attributes and data
22 * to the Storage daemon.
24 * Kern Sibbald, March MM
33 const bool have_lzo = true;
35 const bool have_lzo = false;
39 const bool have_libz = true;
41 const bool have_libz = false;
44 /* Forward referenced functions */
45 int save_file(JCR *jcr, FF_PKT *ff_pkt, bool top_level);
46 static int send_data(bctx_t &bctx, int stream);
47 static void close_vss_backup_session(JCR *jcr);
49 static bool send_resource_fork(bctx_t &bctx);
51 static bool setup_compression(bctx_t &bctx);
52 static bool do_lzo_compression(bctx_t &bctx);
53 static bool do_libz_compression(bctx_t &bctx);
56 * Find all the requested files and send them
57 * to the Storage daemon.
59 * Note, we normally carry on a one-way
60 * conversation from this point on with the SD, simply blasting
61 * data to him. To properly know what is going on, we
62 * also run a "heartbeat" monitor which reads the socket and
63 * reacts accordingly (at the moment it has nothing to do
64 * except echo the heartbeat to the Director).
67 bool blast_data_to_storage_daemon(JCR *jcr, char *addr)
71 // TODO landonf: Allow user to specify encryption algorithm
73 sd = jcr->store_bsock;
75 jcr->setJobStatus(JS_Running);
77 Dmsg1(300, "bfiled: opened data connection %d to stored\n", sd->m_fd);
80 CLIENT *client = (CLIENT *)GetNextRes(R_CLIENT, NULL);
84 buf_size = client->max_network_buffer_size;
86 buf_size = 0; /* use default */
88 if (!sd->set_buffer_size(buf_size, BNET_SETBUF_WRITE)) {
89 jcr->setJobStatus(JS_ErrorTerminated);
90 Jmsg(jcr, M_FATAL, 0, _("Cannot set buffer size FD->SD.\n"));
94 jcr->buf_size = sd->msglen;
96 * Adjust for compression so that output buffer is
97 * 12 bytes + 0.1% larger than input buffer plus 18 bytes.
98 * This gives a bit extra plus room for the sparse addr if any.
99 * Note, we adjust the read size to be smaller so that the
100 * same output buffer can be used without growing it.
102 * For LZO1X compression the recommended value is :
103 * output_block_size = input_block_size + (input_block_size / 16) + 64 + 3 + sizeof(comp_stream_header)
105 * The zlib compression workset is initialized here to minimize
106 * the "per file" load. The jcr member is only set, if the init
109 * For the same reason, lzo compression is initialized here.
112 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);
113 jcr->compress_buf = get_memory(jcr->compress_buf_size);
115 jcr->compress_buf_size = jcr->buf_size + ((jcr->buf_size+999) / 1000) + 30;
116 jcr->compress_buf = get_memory(jcr->compress_buf_size);
120 z_stream *pZlibStream = (z_stream*)malloc(sizeof(z_stream));
122 pZlibStream->zalloc = Z_NULL;
123 pZlibStream->zfree = Z_NULL;
124 pZlibStream->opaque = Z_NULL;
125 pZlibStream->state = Z_NULL;
127 if (deflateInit(pZlibStream, Z_DEFAULT_COMPRESSION) == Z_OK) {
128 jcr->pZLIB_compress_workset = pZlibStream;
136 lzo_voidp pLzoMem = (lzo_voidp) malloc(LZO1X_1_MEM_COMPRESS);
138 if (lzo_init() == LZO_E_OK) {
139 jcr->LZO_compress_workset = pLzoMem;
146 if (!crypto_session_start(jcr)) {
150 set_find_options(jcr->ff, jcr->incremental, jcr->mtime);
151 set_find_snapshot_function(jcr->ff, snapshot_convert_path);
153 /** in accurate mode, we overload the find_one check function */
155 set_find_changed_function((FF_PKT *)jcr->ff, accurate_check_file);
157 start_heartbeat_monitor(jcr);
160 jcr->acl_ctx = (acl_ctx_t *)malloc(sizeof(acl_ctx_t));
161 memset(jcr->acl_ctx, 0, sizeof(acl_ctx_t));
162 jcr->acl_ctx->content = get_pool_memory(PM_MESSAGE);
165 jcr->xattr_ctx = (xattr_ctx_t *)malloc(sizeof(xattr_ctx_t));
166 memset(jcr->xattr_ctx, 0, sizeof(xattr_ctx_t));
167 jcr->xattr_ctx->content = get_pool_memory(PM_MESSAGE);
171 /** Subroutine save_file() is called for each file */
172 if (!find_files(jcr, (FF_PKT *)jcr->ff, save_file, plugin_save)) {
173 ok = false; /* error */
174 jcr->setJobStatus(JS_ErrorTerminated);
178 if (jcr->acl_ctx->nr_errors > 0) {
179 Jmsg(jcr, M_WARNING, 0, _("Had %ld acl errors while doing backup\n"),
180 jcr->acl_ctx->nr_errors);
184 if (jcr->xattr_ctx->nr_errors > 0) {
185 Jmsg(jcr, M_WARNING, 0, _("Had %ld xattr errors while doing backup\n"),
186 jcr->xattr_ctx->nr_errors);
189 /* Delete or keep snapshots */
190 close_snapshot_backup_session(jcr);
191 close_vss_backup_session(jcr);
193 accurate_finish(jcr); /* send deleted or base file list to SD */
195 stop_heartbeat_monitor(jcr);
197 sd->signal(BNET_EOD); /* end of sending data */
202 free_and_null_pool_memory(jcr->acl_ctx->content);
203 bfree_and_null(jcr->acl_ctx);
207 if (jcr->xattr_ctx) {
208 free_and_null_pool_memory(jcr->xattr_ctx->content);
209 bfree_and_null(jcr->xattr_ctx);
213 bfree_and_null(jcr->big_buf);
215 if (jcr->compress_buf) {
216 free_and_null_pool_memory(jcr->compress_buf);
218 if (jcr->pZLIB_compress_workset) {
219 /* Free the zlib stream */
221 deflateEnd((z_stream *)jcr->pZLIB_compress_workset);
223 bfree_and_null(jcr->pZLIB_compress_workset);
225 if (jcr->LZO_compress_workset) {
226 bfree_and_null(jcr->LZO_compress_workset);
229 crypto_session_end(jcr);
232 Dmsg1(100, "end blast_data ok=%d\n", ok);
238 * Called here by find() for each file included.
239 * This is a callback. The original is find_files() above.
241 * Send the file and its data to the Storage daemon.
245 * -1 to ignore file/directory (not used here)
247 int save_file(JCR *jcr, FF_PKT *ff_pkt, bool top_level)
249 bool do_read = false;
250 bool plugin_started = false;
251 bool do_plugin_set = false;
254 bool has_file_data = false;
255 struct save_pkt sp; /* used by option plugin */
256 BSOCK *sd = jcr->store_bsock;
257 bctx_t bctx; /* backup context */
259 memset(&bctx, 0, sizeof(bctx));
261 bctx.ff_pkt = ff_pkt;
265 time_t now = time(NULL);
266 if (jcr->last_stat_time == 0) {
267 jcr->last_stat_time = now;
268 jcr->stat_interval = 30; /* Default 30 seconds */
269 } else if (now >= jcr->last_stat_time + jcr->stat_interval) {
270 jcr->dir_bsock->fsend("Progress Job=x files=%ld bytes=%lld bps=%ld\n",
271 jcr->JobFiles, jcr->JobBytes, jcr->LastRate);
272 jcr->last_stat_time = now;
275 if (jcr->is_canceled() || jcr->is_incomplete()) {
276 Dmsg0(100, "Job canceled by user or marked incomplete.\n");
280 jcr->num_files_examined++; /* bump total file count */
282 switch (ff_pkt->type) {
283 case FT_LNKSAVED: /* Hard linked, file already saved */
284 Dmsg2(130, "FT_LNKSAVED hard link: %s => %s\n", ff_pkt->fname, ff_pkt->link);
287 Dmsg1(130, "FT_REGE saving: %s\n", ff_pkt->fname);
288 has_file_data = true;
291 Dmsg1(130, "FT_REG saving: %s\n", ff_pkt->fname);
292 has_file_data = true;
295 Dmsg2(130, "FT_LNK saving: %s -> %s\n", ff_pkt->fname, ff_pkt->link);
297 case FT_RESTORE_FIRST:
298 Dmsg1(100, "FT_RESTORE_FIRST saving: %s\n", ff_pkt->fname);
300 case FT_PLUGIN_CONFIG:
301 Dmsg1(100, "FT_PLUGIN_CONFIG saving: %s\n", ff_pkt->fname);
304 jcr->num_files_examined--; /* correct file count */
305 return 1; /* not used */
307 Jmsg(jcr, M_INFO, 1, _(" Recursion turned off. Will not descend from %s into %s\n"),
308 ff_pkt->top_fname, ff_pkt->fname);
309 ff_pkt->type = FT_DIREND; /* Backup only the directory entry */
312 /* Suppress message for /dev filesystems */
313 if (!is_in_fileset(ff_pkt)) {
314 Jmsg(jcr, M_INFO, 1, _(" %s is a different filesystem. Will not descend from %s into it.\n"),
315 ff_pkt->fname, ff_pkt->top_fname);
317 ff_pkt->type = FT_DIREND; /* Backup only the directory entry */
320 Jmsg(jcr, M_INFO, 1, _(" Disallowed filesystem. Will not descend from %s into %s\n"),
321 ff_pkt->top_fname, ff_pkt->fname);
322 ff_pkt->type = FT_DIREND; /* Backup only the directory entry */
325 Jmsg(jcr, M_INFO, 1, _(" Disallowed drive type. Will not descend into %s\n"),
331 Dmsg1(130, "FT_DIREND: %s\n", ff_pkt->link);
334 Dmsg1(130, "FT_SPEC saving: %s\n", ff_pkt->fname);
335 if (S_ISSOCK(ff_pkt->statp.st_mode)) {
336 Jmsg(jcr, M_SKIPPED, 1, _(" Socket file skipped: %s\n"), ff_pkt->fname);
341 Dmsg1(130, "FT_RAW saving: %s\n", ff_pkt->fname);
342 has_file_data = true;
345 Dmsg1(130, "FT_FIFO saving: %s\n", ff_pkt->fname);
349 Jmsg(jcr, M_NOTSAVED, 0, _(" Could not access \"%s\": ERR=%s\n"), ff_pkt->fname,
350 be.bstrerror(ff_pkt->ff_errno));
356 Jmsg(jcr, M_NOTSAVED, 0, _(" Could not follow link \"%s\": ERR=%s\n"),
357 ff_pkt->fname, be.bstrerror(ff_pkt->ff_errno));
363 Jmsg(jcr, M_NOTSAVED, 0, _(" Could not stat \"%s\": ERR=%s\n"), ff_pkt->fname,
364 be.bstrerror(ff_pkt->ff_errno));
370 Jmsg(jcr, M_SKIPPED, 1, _(" Unchanged file skipped: %s\n"), ff_pkt->fname);
373 Jmsg(jcr, M_NOTSAVED, 0, _(" Archive file not saved: %s\n"), ff_pkt->fname);
377 Jmsg(jcr, M_NOTSAVED, 0, _(" Could not open directory \"%s\": ERR=%s\n"),
378 ff_pkt->fname, be.bstrerror(ff_pkt->ff_errno));
383 Dmsg1(130, "FT_DELETED: %s\n", ff_pkt->fname);
386 Jmsg(jcr, M_NOTSAVED, 0, _(" Unknown file type %d; not saved: %s\n"),
387 ff_pkt->type, ff_pkt->fname);
392 Dmsg1(130, "bfiled: sending %s to stored\n", ff_pkt->fname);
394 /** Digests and encryption are only useful if there's file data */
395 if (has_file_data && !crypto_setup_digests(bctx)) {
399 /** Initialize the file descriptor we use for data and other streams. */
401 if (ff_pkt->flags & FO_PORTABLE) {
402 set_portable_backup(&ff_pkt->bfd); /* disable Win32 BackupRead() */
405 if (ff_pkt->cmd_plugin) {
406 do_plugin_set = true;
408 /* option and cmd plugin are not compatible together */
409 } else if (ff_pkt->opt_plugin) {
411 /* ask the option plugin what to do with this file */
412 switch (plugin_option_handle_file(jcr, ff_pkt, &sp)) {
414 Dmsg2(10, "Option plugin %s will be used to backup %s\n",
415 ff_pkt->plugin, ff_pkt->fname);
416 do_plugin_set = true;
419 Dmsg2(10, "Option plugin %s decided to skip %s\n",
420 ff_pkt->plugin, ff_pkt->fname);
423 Dmsg2(10, "Option plugin %s decided to let bacula handle %s\n",
424 ff_pkt->plugin, ff_pkt->fname);
430 /* Tell bfile that it needs to call plugin */
431 if (!set_cmd_plugin(&ff_pkt->bfd, jcr)) {
434 send_plugin_name(jcr, sd, true); /* signal start of plugin data */
435 plugin_started = true;
438 /** Send attributes -- must be done after binit() */
439 if (!encode_and_send_attributes(bctx)) {
442 /** Meta data only for restore object */
443 if (IS_FT_OBJECT(ff_pkt->type)) {
446 /** Meta data only for deleted files */
447 if (ff_pkt->type == FT_DELETED) {
450 /** Set up the encryption context and send the session data to the SD */
451 if (has_file_data && jcr->crypto.pki_encrypt) {
452 if (!crypto_session_send(jcr, sd)) {
458 * Open any file with data that we intend to save, then save it.
460 * Note, if is_win32_backup, we must open the Directory so that
461 * the BackupRead will save its permissions and ownership streams.
463 if (ff_pkt->type != FT_LNKSAVED && S_ISREG(ff_pkt->statp.st_mode)) {
465 do_read = !is_portable_backup(&ff_pkt->bfd) || ff_pkt->statp.st_size > 0;
467 do_read = ff_pkt->statp.st_size > 0;
469 } else if (ff_pkt->type == FT_RAW || ff_pkt->type == FT_FIFO ||
470 ff_pkt->type == FT_REPARSE || ff_pkt->type == FT_JUNCTION ||
471 (!is_portable_backup(&ff_pkt->bfd) && ff_pkt->type == FT_DIREND)) {
475 if (ff_pkt->cmd_plugin && !ff_pkt->no_read) {
479 Dmsg2(150, "type=%d do_read=%d\n", ff_pkt->type, do_read);
483 if (ff_pkt->type == FT_FIFO) {
484 tid = start_thread_timer(jcr, pthread_self(), 60);
488 int noatime = ff_pkt->flags & FO_NOATIME ? O_NOATIME : 0;
489 ff_pkt->bfd.reparse_point = (ff_pkt->type == FT_REPARSE ||
490 ff_pkt->type == FT_JUNCTION);
491 set_fattrs(&ff_pkt->bfd, &ff_pkt->statp);
492 if (bopen(&ff_pkt->bfd, ff_pkt->fname, O_RDONLY | O_BINARY | noatime, 0) < 0) {
493 ff_pkt->ff_errno = errno;
495 Jmsg(jcr, M_NOTSAVED, 0, _(" Cannot open \"%s\": ERR=%s.\n"), ff_pkt->fname,
499 stop_thread_timer(tid);
505 stop_thread_timer(tid);
509 stat = send_data(bctx, bctx.data_stream);
511 if (ff_pkt->flags & FO_CHKCHANGES) {
512 has_file_changed(jcr, ff_pkt);
515 bclose(&ff_pkt->bfd);
522 #ifdef HAVE_DARWIN_OS
523 if (!send_resource_fork(bctx)) {
529 * Save ACLs when requested and available for anything not being a symlink
530 * and not being a plugin.
533 if (!backup_acl_streams(jcr, ff_pkt)) {
539 * Save Extended Attributes when requested and available for all files not
543 if (!backup_xattr_streams(jcr, ff_pkt)) {
548 if (!crypto_terminate_digests(bctx)) {
556 if (jcr->is_incomplete() || jcr->is_canceled()) {
557 Dmsg0(100, "Job canceled by user or marked incomplete.\n");
560 if (plugin_started) {
561 send_plugin_name(jcr, sd, false); /* signal end of plugin data */
563 if (ff_pkt->opt_plugin) {
564 jcr->plugin_sp = NULL; /* sp is local to this function */
565 jcr->plugin_ctx = NULL;
567 jcr->opt_plugin = false;
574 * Send data read from an already open file descriptor.
576 * We return 1 on success and 0 on errors.
579 * We use ff_pkt->statp.st_size when FO_SPARSE to know when to stop
581 * Currently this is not a problem as the only other stream, resource forks,
582 * are not handled as sparse files.
584 static int send_data(bctx_t &bctx, int stream)
587 BSOCK *sd = jcr->store_bsock;
589 #ifdef FD_NO_SEND_TEST
593 bctx.rsize = jcr->buf_size;
595 bctx.cipher_ctx = NULL;
596 bctx.msgsave = sd->msg;
597 bctx.rbuf = sd->msg; /* read buffer */
598 bctx.wbuf = sd->msg; /* write buffer */
599 bctx.cipher_input = (uint8_t *)bctx.rbuf; /* encrypt uncompressed data */
601 Dmsg1(300, "Saving data, type=%d\n", bctx.ff_pkt->type);
603 if (!setup_compression(bctx)) {
607 if (bctx.ff_pkt->flags & FO_ENCRYPT && !crypto_allocate_ctx(bctx)) {
612 * Send Data header to Storage daemon
613 * <file-index> <stream> <expected stream length>
615 if (!sd->fsend("%ld %d %lld", jcr->JobFiles, stream,
616 (int64_t)bctx.ff_pkt->statp.st_size)) {
617 if (!jcr->is_job_canceled()) {
618 Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
623 Dmsg1(300, ">stored: datahdr %s\n", sd->msg);
626 * Make space at beginning of buffer for fileAddr because this
627 * same buffer will be used for writing if compression is off.
629 if ((bctx.ff_pkt->flags & FO_SPARSE) || (bctx.ff_pkt->flags & FO_OFFSETS)) {
630 bctx.rbuf += OFFSET_FADDR_SIZE;
631 bctx.rsize -= OFFSET_FADDR_SIZE;
632 #ifdef HAVE_FREEBSD_OS
634 * To read FreeBSD partitions, the read size must be
637 bctx.rsize = (bctx.rsize/512) * 512;
641 /** a RAW device read on win32 only works if the buffer is a multiple of 512 */
643 if (S_ISBLK(bctx.ff_pkt->statp.st_mode)) {
644 bctx.rsize = (bctx.rsize/512) * 512;
646 Dmsg1(200, "Fattrs=0X%x\n", bctx.ff_pkt->bfd.fattrs);
647 if (bctx.ff_pkt->bfd.fattrs & FILE_ATTRIBUTE_ENCRYPTED) {
648 if (!p_ReadEncryptedFileRaw) {
649 Jmsg0(bctx.jcr, M_FATAL, 0, _("Windows Encrypted data not supported on this OS.\n"));
652 /* This single call reads all EFS data delivers it to a callback */
653 if (p_ReadEncryptedFileRaw((PFE_EXPORT_FUNC)read_efs_data_cb, &bctx,
654 bctx.ff_pkt->bfd.pvContext) != 0) {
657 /* All read, so skip to finish sending */
660 /* Fall through to standard bread() loop */
664 * Normal read the file data in a loop and send it to SD
666 while ((sd->msglen=(uint32_t)bread(&bctx.ff_pkt->bfd, bctx.rbuf, bctx.rsize)) > 0) {
667 if (!process_and_send_data(bctx)) {
670 } /* end while read file data */
674 if (sd->msglen < 0) { /* error */
676 Jmsg(jcr, M_ERROR, 0, _("Read error on file %s. ERR=%s\n"),
677 bctx.ff_pkt->fname, be.bstrerror(bctx.ff_pkt->bfd.berrno));
678 if (jcr->JobErrors++ > 1000) { /* insanity check */
679 Jmsg(jcr, M_FATAL, 0, _("Too many errors. JobErrors=%d.\n"), jcr->JobErrors);
681 } else if (bctx.ff_pkt->flags & FO_ENCRYPT) {
683 * For encryption, we must call finalize to push out any
686 if (!crypto_cipher_finalize(bctx.cipher_ctx, (uint8_t *)jcr->crypto.crypto_buf,
687 &bctx.encrypted_len)) {
688 /* Padding failed. Shouldn't happen. */
689 Jmsg(jcr, M_FATAL, 0, _("Encryption padding error\n"));
693 /** Note, on SSL pre-0.9.7, there is always some output */
694 if (bctx.encrypted_len > 0) {
695 sd->msglen = bctx.encrypted_len; /* set encrypted length */
696 sd->msg = jcr->crypto.crypto_buf; /* set correct write buffer */
698 if (!jcr->is_job_canceled()) {
699 Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
704 Dmsg1(130, "Send data to SD len=%d\n", sd->msglen);
705 jcr->JobBytes += sd->msglen; /* count bytes saved possibly compressed/encrypted */
706 sd->msg = bctx.msgsave; /* restore bnet buffer */
711 if (!sd->signal(BNET_EOD)) { /* indicate end of file data */
712 if (!jcr->is_job_canceled()) {
713 Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
719 /** Free the cipher context */
720 if (bctx.cipher_ctx) {
721 crypto_cipher_free(bctx.cipher_ctx);
726 /** Free the cipher context */
727 if (bctx.cipher_ctx) {
728 crypto_cipher_free(bctx.cipher_ctx);
731 sd->msg = bctx.msgsave; /* restore bnet buffer */
738 * Apply processing (sparse, compression, encryption, and
741 bool process_and_send_data(bctx_t &bctx)
746 /** Check for sparse blocks */
747 if (bctx.ff_pkt->flags & FO_SPARSE) {
749 bool allZeros = false;
750 if ((sd->msglen == bctx.rsize &&
751 bctx.fileAddr+sd->msglen < (uint64_t)bctx.ff_pkt->statp.st_size) ||
752 ((bctx.ff_pkt->type == FT_RAW || bctx.ff_pkt->type == FT_FIFO) &&
753 (uint64_t)bctx.ff_pkt->statp.st_size == 0)) {
754 allZeros = is_buf_zero(bctx.rbuf, bctx.rsize);
757 /** Put file address as first data in buffer */
758 ser_begin(bctx.wbuf, OFFSET_FADDR_SIZE);
759 ser_uint64(bctx.fileAddr); /* store fileAddr in begin of buffer */
761 bctx.fileAddr += sd->msglen; /* update file address */
762 /** Skip block of all zeros */
764 return true; /* skip block of zeros */
766 } else if (bctx.ff_pkt->flags & FO_OFFSETS) {
768 ser_begin(bctx.wbuf, OFFSET_FADDR_SIZE);
769 ser_uint64(bctx.ff_pkt->bfd.offset); /* store offset in begin of buffer */
772 jcr->ReadBytes += sd->msglen; /* count bytes read */
774 /** Uncompressed cipher input length */
775 bctx.cipher_input_len = sd->msglen;
777 /** Update checksum if requested */
779 crypto_digest_update(bctx.digest, (uint8_t *)bctx.rbuf, sd->msglen);
782 /** Update signing digest if requested */
783 if (bctx.signing_digest) {
784 crypto_digest_update(bctx.signing_digest, (uint8_t *)bctx.rbuf, sd->msglen);
787 if (have_libz && !do_libz_compression(bctx)) {
791 if (have_lzo && !do_lzo_compression(bctx)) {
796 * Note, here we prepend the current record length to the beginning
797 * of the encrypted data. This is because both sparse and compression
798 * restore handling want records returned to them with exactly the
799 * same number of bytes that were processed in the backup handling.
800 * That is, both are block filters rather than a stream. When doing
801 * compression, the compression routines may buffer data, so that for
802 * any one record compressed, when it is decompressed the same size
803 * will not be obtained. Of course, the buffered data eventually comes
804 * out in subsequent crypto_cipher_update() calls or at least
805 * when crypto_cipher_finalize() is called. Unfortunately, this
806 * "feature" of encryption enormously complicates the restore code.
808 if (bctx.ff_pkt->flags & FO_ENCRYPT) {
809 uint32_t initial_len = 0;
812 if ((bctx.ff_pkt->flags & FO_SPARSE) || (bctx.ff_pkt->flags & FO_OFFSETS)) {
813 bctx.cipher_input_len += OFFSET_FADDR_SIZE;
816 /** Encrypt the length of the input block */
817 uint8_t packet_len[sizeof(uint32_t)];
819 ser_begin(packet_len, sizeof(uint32_t));
820 ser_uint32(bctx.cipher_input_len); /* store data len in begin of buffer */
821 Dmsg1(20, "Encrypt len=%d\n", bctx.cipher_input_len);
823 if (!crypto_cipher_update(bctx.cipher_ctx, packet_len, sizeof(packet_len),
824 (uint8_t *)jcr->crypto.crypto_buf, &initial_len)) {
825 /** Encryption failed. Shouldn't happen. */
826 Jmsg(jcr, M_FATAL, 0, _("Encryption error\n"));
830 /** Encrypt the input block */
831 if (crypto_cipher_update(bctx.cipher_ctx, bctx.cipher_input, bctx.cipher_input_len,
832 (uint8_t *)&jcr->crypto.crypto_buf[initial_len], &bctx.encrypted_len)) {
833 if ((initial_len + bctx.encrypted_len) == 0) {
834 /** No full block of data available, read more data */
837 Dmsg2(400, "encrypted len=%d unencrypted len=%d\n", bctx.encrypted_len,
839 sd->msglen = initial_len + bctx.encrypted_len; /* set encrypted length */
841 /** Encryption failed. Shouldn't happen. */
842 Jmsg(jcr, M_FATAL, 0, _("Encryption error\n"));
847 /* Send the buffer to the Storage daemon */
848 if ((bctx.ff_pkt->flags & FO_SPARSE) || (bctx.ff_pkt->flags & FO_OFFSETS)) {
849 sd->msglen += OFFSET_FADDR_SIZE; /* include fileAddr in size */
851 sd->msg = bctx.wbuf; /* set correct write buffer */
853 if (!jcr->is_job_canceled()) {
854 Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
859 Dmsg1(130, "Send data to SD len=%d\n", sd->msglen);
861 jcr->JobBytes += sd->msglen; /* count bytes saved possibly compressed/encrypted */
862 sd->msg = bctx.msgsave; /* restore read buffer */
869 bool encode_and_send_attributes(bctx_t &bctx)
871 BSOCK *sd = bctx.jcr->store_bsock;
873 FF_PKT *ff_pkt = bctx.ff_pkt;
874 char attribs[MAXSTRING];
875 char attribsExBuf[MAXSTRING];
876 char *attribsEx = NULL;
880 int hangup = get_hangup();
881 int blowup = get_blowup();
882 #ifdef FD_NO_SEND_TEST
886 Dmsg1(300, "encode_and_send_attrs fname=%s\n", ff_pkt->fname);
887 /** Find what data stream we will use, then encode the attributes */
888 if ((bctx.data_stream = select_data_stream(ff_pkt)) == STREAM_NONE) {
889 /* This should not happen */
890 Jmsg0(jcr, M_FATAL, 0, _("Invalid file flags, no supported data stream type.\n"));
893 encode_stat(attribs, &ff_pkt->statp, sizeof(ff_pkt->statp), ff_pkt->LinkFI, bctx.data_stream);
895 /** Now possibly extend the attributes */
896 if (IS_FT_OBJECT(ff_pkt->type)) {
897 attr_stream = STREAM_RESTORE_OBJECT;
899 attribsEx = attribsExBuf;
900 attr_stream = encode_attribsEx(jcr, attribsEx, ff_pkt);
903 Dmsg3(300, "File %s\nattribs=%s\nattribsEx=%s\n", ff_pkt->fname, attribs, attribsEx);
906 jcr->JobFiles++; /* increment number of files sent */
907 ff_pkt->FileIndex = jcr->JobFiles; /* return FileIndex */
908 pm_strcpy(jcr->last_fname, ff_pkt->fname);
911 /* Debug code: check if we must hangup */
912 if (hangup > 0 && (jcr->JobFiles > (uint32_t)hangup)) {
913 jcr->setJobStatus(JS_Incomplete);
914 Jmsg1(jcr, M_FATAL, 0, "Debug hangup requested after %d files.\n", hangup);
919 if (blowup > 0 && (jcr->JobFiles > (uint32_t)blowup)) {
920 Jmsg1(jcr, M_ABORT, 0, "Debug blowup requested after %d files.\n", blowup);
925 * Send Attributes header to Storage daemon
926 * <file-index> <stream> <info>
928 if (!sd->fsend("%ld %d 0", jcr->JobFiles, attr_stream)) {
929 if (!jcr->is_canceled() && !jcr->is_incomplete()) {
930 Jmsg2(jcr, M_FATAL, 0, _("Network send error to SD. Data=%s ERR=%s\n"),
931 sd->msg, sd->bstrerror());
935 Dmsg1(300, ">stored: attrhdr %s\n", sd->msg);
938 * Send file attributes to Storage daemon
941 * Filename (full path)
943 * Link name (if type==FT_LNK or FT_LNKSAVED)
944 * Encoded extended-attributes (for Win32)
946 * or send Restore Object to Storage daemon
950 * Object_len (possibly compressed)
951 * Object_full_len (not compressed)
957 * For a directory, link is the same as fname, but with trailing
958 * slash. For a linked file, link is the link.
960 if (!IS_FT_OBJECT(ff_pkt->type) && ff_pkt->type != FT_DELETED) { /* already stripped */
963 switch (ff_pkt->type) {
966 Dmsg3(300, "Link %d %s to %s\n", jcr->JobFiles, ff_pkt->fname, ff_pkt->link);
967 stat = sd->fsend("%ld %d %s%c%s%c%s%c%s%c%u%c", jcr->JobFiles,
968 ff_pkt->type, ff_pkt->fname, 0, attribs, 0,
969 ff_pkt->link, 0, attribsEx, 0, ff_pkt->delta_seq, 0);
974 /* Here link is the canonical filename (i.e. with trailing slash) */
975 stat = sd->fsend("%ld %d %s%c%s%c%c%s%c%u%c", jcr->JobFiles,
976 ff_pkt->type, ff_pkt->link, 0, attribs, 0, 0,
977 attribsEx, 0, ff_pkt->delta_seq, 0);
979 case FT_PLUGIN_CONFIG:
980 case FT_RESTORE_FIRST:
981 comp_len = ff_pkt->object_len;
982 ff_pkt->object_compression = 0;
983 if (ff_pkt->object_len > 1000) {
984 /* Big object, compress it */
985 comp_len = ff_pkt->object_len + 1000;
986 POOLMEM *comp_obj = get_memory(comp_len);
987 /* *** FIXME *** check Zdeflate error */
988 Zdeflate(ff_pkt->object, ff_pkt->object_len, comp_obj, comp_len);
989 if (comp_len < ff_pkt->object_len) {
990 ff_pkt->object = comp_obj;
991 ff_pkt->object_compression = 1; /* zlib level 9 compression */
993 /* Uncompressed object smaller, use it */
994 comp_len = ff_pkt->object_len;
996 Dmsg2(100, "Object compressed from %d to %d bytes\n", ff_pkt->object_len, comp_len);
998 sd->msglen = Mmsg(sd->msg, "%d %d %d %d %d %d %s%c%s%c",
999 jcr->JobFiles, ff_pkt->type, ff_pkt->object_index,
1000 comp_len, ff_pkt->object_len, ff_pkt->object_compression,
1001 ff_pkt->fname, 0, ff_pkt->object_name, 0);
1002 sd->msg = check_pool_memory_size(sd->msg, sd->msglen + comp_len + 2);
1003 memcpy(sd->msg + sd->msglen, ff_pkt->object, comp_len);
1004 /* Note we send one extra byte so Dir can store zero after object */
1005 sd->msglen += comp_len + 1;
1007 if (ff_pkt->object_compression) {
1008 free_and_null_pool_memory(ff_pkt->object);
1012 stat = sd->fsend("%ld %d %s%c%s%c%c%s%c%d%c", jcr->JobFiles,
1013 ff_pkt->type, ff_pkt->fname, 0, attribs, 0, 0, attribsEx, 0,
1014 ff_pkt->delta_seq, 0);
1017 stat = sd->fsend("%ld %d %s%c%s%c%c%s%c%u%c", jcr->JobFiles,
1018 ff_pkt->type, ff_pkt->fname, 0, attribs, 0, 0,
1019 attribsEx, 0, ff_pkt->delta_seq, 0);
1023 if (!IS_FT_OBJECT(ff_pkt->type) && ff_pkt->type != FT_DELETED) {
1024 unstrip_path(ff_pkt);
1027 Dmsg2(300, ">stored: attr len=%d: %s\n", sd->msglen, sd->msg);
1028 if (!stat && !jcr->is_job_canceled()) {
1029 Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
1032 sd->signal(BNET_EOD); /* indicate end of attributes data */
1037 * Setup bctx for doing compression
1039 static bool setup_compression(bctx_t &bctx)
1041 JCR *jcr = bctx.jcr;
1043 #if defined(HAVE_LIBZ) || defined(HAVE_LZO)
1044 bctx.compress_len = 0;
1045 bctx.max_compress_len = 0;
1050 if ((bctx.ff_pkt->flags & FO_COMPRESS) && bctx.ff_pkt->Compress_algo == COMPRESS_GZIP) {
1051 if ((bctx.ff_pkt->flags & FO_SPARSE) || (bctx.ff_pkt->flags & FO_OFFSETS)) {
1052 bctx.cbuf = (Bytef *)jcr->compress_buf + OFFSET_FADDR_SIZE;
1053 bctx.max_compress_len = jcr->compress_buf_size - OFFSET_FADDR_SIZE;
1055 bctx.cbuf = (Bytef *)jcr->compress_buf;
1056 bctx.max_compress_len = jcr->compress_buf_size; /* set max length */
1058 bctx.wbuf = jcr->compress_buf; /* compressed output here */
1059 bctx.cipher_input = (uint8_t *)jcr->compress_buf; /* encrypt compressed data */
1062 * Only change zlib parameters if there is no pending operation.
1063 * This should never happen as deflatereset is called after each
1067 if (((z_stream*)jcr->pZLIB_compress_workset)->total_in == 0) {
1068 /** set gzip compression level - must be done per file */
1069 if ((zstat=deflateParams((z_stream*)jcr->pZLIB_compress_workset,
1070 bctx.ff_pkt->Compress_level, Z_DEFAULT_STRATEGY)) != Z_OK) {
1071 Jmsg(jcr, M_FATAL, 0, _("Compression deflateParams error: %d\n"), zstat);
1072 jcr->setJobStatus(JS_ErrorTerminated);
1079 memset(&bctx.ch, 0, sizeof(comp_stream_header));
1082 if ((bctx.ff_pkt->flags & FO_COMPRESS) && bctx.ff_pkt->Compress_algo == COMPRESS_LZO1X) {
1083 if ((bctx.ff_pkt->flags & FO_SPARSE) || (bctx.ff_pkt->flags & FO_OFFSETS)) {
1084 bctx.cbuf = (Bytef *)jcr->compress_buf + OFFSET_FADDR_SIZE;
1085 bctx.cbuf2 = (Bytef *)jcr->compress_buf + OFFSET_FADDR_SIZE + sizeof(comp_stream_header);
1086 bctx.max_compress_len = jcr->compress_buf_size - OFFSET_FADDR_SIZE;
1088 bctx.cbuf = (Bytef *)jcr->compress_buf;
1089 bctx.cbuf2 = (Bytef *)jcr->compress_buf + sizeof(comp_stream_header);
1090 bctx.max_compress_len = jcr->compress_buf_size; /* set max length */
1092 bctx.ch.magic = COMPRESS_LZO1X;
1093 bctx.ch.version = COMP_HEAD_VERSION;
1094 bctx.wbuf = jcr->compress_buf; /* compressed output here */
1095 bctx.cipher_input = (uint8_t *)jcr->compress_buf; /* encrypt compressed data */
1099 bctx.max_compress_len = 0;
1105 * Send MacOS resource fork to SD
1107 #ifdef HAVE_DARWIN_OS
1108 static bool send_resource_fork(bctx_t &bctx)
1110 FF_PKT *ff_pkt = bctx.ff_pkt;
1111 JCR *jcr = bctx.jcr;
1112 BSOCK *sd = bctx.sd;
1115 /** Regular files can have resource forks and Finder Info */
1116 if (ff_pkt->type != FT_LNKSAVED && (S_ISREG(ff_pkt->statp.st_mode) &&
1117 ff_pkt->flags & FO_HFSPLUS)) {
1118 if (ff_pkt->hfsinfo.rsrclength > 0) {
1121 if (bopen_rsrc(&ff_pkt->bfd, ff_pkt->fname, O_RDONLY | O_BINARY, 0) < 0) {
1122 ff_pkt->ff_errno = errno;
1124 Jmsg(jcr, M_NOTSAVED, -1, _(" Cannot open resource fork for \"%s\": ERR=%s.\n"),
1125 ff_pkt->fname, be.bstrerror());
1127 if (is_bopen(&ff_pkt->bfd)) {
1128 bclose(&ff_pkt->bfd);
1132 flags = ff_pkt->flags;
1133 ff_pkt->flags &= ~(FO_COMPRESS|FO_SPARSE|FO_OFFSETS);
1134 if (flags & FO_ENCRYPT) {
1135 rsrc_stream = STREAM_ENCRYPTED_MACOS_FORK_DATA;
1137 rsrc_stream = STREAM_MACOS_FORK_DATA;
1139 stat = send_data(bctx, rsrc_stream);
1140 ff_pkt->flags = flags;
1141 bclose(&ff_pkt->bfd);
1147 Dmsg1(300, "Saving Finder Info for \"%s\"\n", ff_pkt->fname);
1148 sd->fsend("%ld %d 0", jcr->JobFiles, STREAM_HFSPLUS_ATTRIBUTES);
1149 Dmsg1(300, "bfiled>stored:header %s\n", sd->msg);
1150 pm_memcpy(sd->msg, ff_pkt->hfsinfo.fndrinfo, 32);
1153 crypto_digest_update(bctx.digest, (uint8_t *)sd->msg, sd->msglen);
1155 if (bctx.signing_digest) {
1156 crypto_digest_update(bctx.signing_digest, (uint8_t *)sd->msg, sd->msglen);
1159 sd->signal(BNET_EOD);
1165 static bool do_libz_compression(bctx_t &bctx)
1168 JCR *jcr = bctx.jcr;
1169 BSOCK *sd = bctx.sd;
1172 /** Do compression if turned on */
1173 if (bctx.ff_pkt->flags & FO_COMPRESS && bctx.ff_pkt->Compress_algo == COMPRESS_GZIP && jcr->pZLIB_compress_workset) {
1174 Dmsg3(400, "cbuf=0x%x rbuf=0x%x len=%u\n", bctx.cbuf, bctx.rbuf, sd->msglen);
1176 ((z_stream*)jcr->pZLIB_compress_workset)->next_in = (Bytef *)bctx.rbuf;
1177 ((z_stream*)jcr->pZLIB_compress_workset)->avail_in = sd->msglen;
1178 ((z_stream*)jcr->pZLIB_compress_workset)->next_out = bctx.cbuf;
1179 ((z_stream*)jcr->pZLIB_compress_workset)->avail_out = bctx.max_compress_len;
1181 if ((zstat=deflate((z_stream*)jcr->pZLIB_compress_workset, Z_FINISH)) != Z_STREAM_END) {
1182 Jmsg(jcr, M_FATAL, 0, _("Compression deflate error: %d\n"), zstat);
1183 jcr->setJobStatus(JS_ErrorTerminated);
1186 bctx.compress_len = ((z_stream*)jcr->pZLIB_compress_workset)->total_out;
1187 /** reset zlib stream to be able to begin from scratch again */
1188 if ((zstat=deflateReset((z_stream*)jcr->pZLIB_compress_workset)) != Z_OK) {
1189 Jmsg(jcr, M_FATAL, 0, _("Compression deflateReset error: %d\n"), zstat);
1190 jcr->setJobStatus(JS_ErrorTerminated);
1194 Dmsg2(400, "GZIP compressed len=%d uncompressed len=%d\n", bctx.compress_len,
1197 sd->msglen = bctx.compress_len; /* set compressed length */
1198 bctx.cipher_input_len = bctx.compress_len;
1204 static bool do_lzo_compression(bctx_t &bctx)
1207 JCR *jcr = bctx.jcr;
1208 BSOCK *sd = bctx.sd;
1211 /** Do compression if turned on */
1212 if (bctx.ff_pkt->flags & FO_COMPRESS && bctx.ff_pkt->Compress_algo == COMPRESS_LZO1X && jcr->LZO_compress_workset) {
1213 lzo_uint len; /* TODO: See with the latest patch how to handle lzo_uint with 64bit */
1216 ser_begin(bctx.cbuf, sizeof(comp_stream_header));
1218 Dmsg3(400, "cbuf=0x%x rbuf=0x%x len=%u\n", bctx.cbuf, bctx.rbuf, sd->msglen);
1220 lzores = lzo1x_1_compress((const unsigned char*)bctx.rbuf, sd->msglen, bctx.cbuf2,
1221 &len, jcr->LZO_compress_workset);
1222 bctx.compress_len = len;
1223 if (lzores == LZO_E_OK && bctx.compress_len <= bctx.max_compress_len) {
1224 /* complete header */
1225 ser_uint32(COMPRESS_LZO1X);
1226 ser_uint32(bctx.compress_len);
1227 ser_uint16(bctx.ch.level);
1228 ser_uint16(bctx.ch.version);
1230 /** this should NEVER happen */
1231 Jmsg(jcr, M_FATAL, 0, _("Compression LZO error: %d\n"), lzores);
1232 jcr->setJobStatus(JS_ErrorTerminated);
1236 Dmsg2(400, "LZO compressed len=%d uncompressed len=%d\n", bctx.compress_len,
1239 bctx.compress_len += sizeof(comp_stream_header); /* add size of header */
1240 sd->msglen = bctx.compress_len; /* set compressed length */
1241 bctx.cipher_input_len = bctx.compress_len;
1248 * Do in place strip of path
1250 static bool do_snap_strip(FF_PKT *ff)
1252 /* if the string starts with the snapshot path name, we can replace
1253 * by the volume name. The volume_path is smaller than the snapshot_path
1254 * snapshot_path = volume_path + /.snapshots/job-xxxx
1256 ASSERT(strlen(ff->snapshot_path) > strlen(ff->volume_path));
1257 int sp_first = strlen(ff->snapshot_path); /* point after snapshot_path in fname */
1258 if (strncmp(ff->fname, 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->fname[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->fname[sp_first] != '/') {
1268 pm_strcat(ff->snap_fname, "/");
1272 pm_strcat(ff->snap_fname, ff->fname + sp_first);
1273 ASSERT(strlen(ff->fname) > strlen(ff->snap_fname));
1274 strcpy(ff->fname, ff->snap_fname);
1275 Dmsg2(DT_SNAPSHOT|20, "%s -> %s\n", ff->fname_save, ff->fname);
1277 if (strncmp(ff->link, ff->snapshot_path, sp_first) == 0) {
1278 int last = pm_strcpy(ff->snap_fname, ff->volume_path);
1279 last = MAX(last - 1, 0);
1281 if (ff->snap_fname[last] == '/') {
1282 if (ff->link[sp_first] == '/') { /* compare with the first character of the string (sp_first not sp_first-1) */
1283 ff->snap_fname[last] = 0;
1286 if (ff->link[sp_first] != '/') {
1287 pm_strcat(ff->snap_fname, "/");
1291 pm_strcat(ff->snap_fname, ff->link + sp_first);
1292 ASSERT(strlen(ff->link) > strlen(ff->snap_fname));
1293 strcpy(ff->link, ff->snap_fname);
1294 Dmsg2(DT_SNAPSHOT|20, "%s -> %s\n", ff->link_save, ff->link);
1301 * Do in place strip of path
1303 static bool do_strip(int count, char *in)
1309 /** Copy to first path separator -- Win32 might have c: ... */
1310 while (*in && !IsPathSeparator(*in)) {
1313 if (*in) { /* Not at the end of the string */
1315 numsep++; /* one separator seen */
1317 for (stripped=0; stripped<count && *in; stripped++) {
1318 while (*in && !IsPathSeparator(*in)) {
1319 in++; /* skip chars */
1322 numsep++; /* count separators seen */
1323 in++; /* skip separator */
1327 while (*in) { /* copy to end */
1328 if (IsPathSeparator(*in)) {
1334 Dmsg4(500, "stripped=%d count=%d numsep=%d sep>count=%d\n",
1335 stripped, count, numsep, numsep>count);
1336 return stripped==count && numsep>count;
1340 * If requested strip leading components of the path so that we can
1341 * save file as if it came from a subdirectory. This is most useful
1342 * for dealing with snapshots, by removing the snapshot directory, or
1343 * in handling vendor migrations where files have been restored with
1344 * a vendor product into a subdirectory.
1346 * When we are using snapshots, we might need to convert the path
1347 * back to the original one using the strip_snap_path option.
1349 void strip_path(FF_PKT *ff_pkt)
1351 if (!ff_pkt->strip_snap_path &&
1352 (!(ff_pkt->flags & FO_STRIPPATH) || ff_pkt->strip_path <= 0))
1354 Dmsg1(200, "No strip for %s\n", ff_pkt->fname);
1357 /* shared part between strip and snapshot */
1358 if (!ff_pkt->fname_save) {
1359 ff_pkt->fname_save = get_pool_memory(PM_FNAME);
1360 ff_pkt->link_save = get_pool_memory(PM_FNAME);
1361 *ff_pkt->link_save = 0;
1363 pm_strcpy(ff_pkt->fname_save, ff_pkt->fname);
1364 if (ff_pkt->type != FT_LNK && ff_pkt->fname != ff_pkt->link) {
1365 pm_strcpy(ff_pkt->link_save, ff_pkt->link);
1366 Dmsg2(500, "strcpy link_save=%d link=%d\n", strlen(ff_pkt->link_save),
1367 strlen(ff_pkt->link));
1371 if (ff_pkt->strip_snap_path) {
1372 if (!do_snap_strip(ff_pkt)) {
1373 Dmsg1(0, "Something wrong with do_snap_strip(%s)\n", ff_pkt->fname);
1374 unstrip_path(ff_pkt);
1379 /* See if we want also to strip the path */
1380 if (!(ff_pkt->flags & FO_STRIPPATH) || ff_pkt->strip_path <= 0) {
1385 * Strip path. If it doesn't succeed put it back. If
1386 * it does, and there is a different link string,
1387 * attempt to strip the link. If it fails, back them
1389 * Do not strip symlinks.
1390 * I.e. if either stripping fails don't strip anything.
1392 if (!do_strip(ff_pkt->strip_path, ff_pkt->fname)) {
1393 unstrip_path(ff_pkt);
1396 /** Strip links but not symlinks */
1397 if (ff_pkt->type != FT_LNK && ff_pkt->fname != ff_pkt->link) {
1398 if (!do_strip(ff_pkt->strip_path, ff_pkt->link)) {
1399 unstrip_path(ff_pkt);
1404 Dmsg3(10, "fname=%s stripped=%s link=%s\n", ff_pkt->fname_save, ff_pkt->fname,
1408 void unstrip_path(FF_PKT *ff_pkt)
1410 if (!ff_pkt->strip_snap_path &&
1411 (!(ff_pkt->flags & FO_STRIPPATH) || ff_pkt->strip_path <= 0))
1416 strcpy(ff_pkt->fname, ff_pkt->fname_save);
1417 if (ff_pkt->type != FT_LNK && ff_pkt->fname != ff_pkt->link) {
1418 Dmsg2(10, "strcpy link=%s link_save=%s\n", ff_pkt->link,
1420 strcpy(ff_pkt->link, ff_pkt->link_save);
1421 Dmsg2(10, "strcpy link=%d link_save=%d\n", strlen(ff_pkt->link),
1422 strlen(ff_pkt->link_save));
1427 static void close_vss_backup_session(JCR *jcr)
1429 #if defined(WIN32_VSS)
1430 /* STOP VSS ON WIN32 */
1431 /* tell vss to close the backup session */
1432 if (jcr->Snapshot) {
1433 if (g_pVSSClient->CloseBackup()) {
1434 /* inform user about writer states */
1435 for (int i=0; i<(int)g_pVSSClient->GetWriterCount(); i++) {
1436 int msg_type = M_INFO;
1437 if (g_pVSSClient->GetWriterState(i) < 1) {
1438 msg_type = M_WARNING;
1441 Jmsg(jcr, msg_type, 0, _("VSS Writer (BackupComplete): %s\n"), g_pVSSClient->GetWriterInfo(i));
1444 /* Generate Job global writer metadata */
1445 WCHAR *metadata = g_pVSSClient->GetMetadata();
1447 FF_PKT *ff_pkt = jcr->ff;
1448 ff_pkt->fname = (char *)"*all*"; /* for all plugins */
1449 ff_pkt->type = FT_RESTORE_FIRST;
1451 ff_pkt->object_name = (char *)"job_metadata.xml";
1452 ff_pkt->object = (char *)metadata;
1453 ff_pkt->object_len = (wcslen(metadata) + 1) * sizeof(WCHAR);
1454 ff_pkt->object_index = (int)time(NULL);
1455 save_file(jcr, ff_pkt, true);