2 Bacula(R) - The Network Backup Solution
4 Copyright (C) 2000-2015 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);
159 jcr->acl_ctx = (acl_ctx_t *)malloc(sizeof(acl_ctx_t));
160 memset(jcr->acl_ctx, 0, sizeof(acl_ctx_t));
161 jcr->acl_ctx->content = get_pool_memory(PM_MESSAGE);
164 jcr->xattr_ctx = (xattr_ctx_t *)malloc(sizeof(xattr_ctx_t));
165 memset(jcr->xattr_ctx, 0, sizeof(xattr_ctx_t));
166 jcr->xattr_ctx->content = get_pool_memory(PM_MESSAGE);
169 /* Subroutine save_file() is called for each file */
170 if (!find_files(jcr, (FF_PKT *)jcr->ff, save_file, plugin_save)) {
171 ok = false; /* error */
172 jcr->setJobStatus(JS_ErrorTerminated);
176 if (jcr->acl_ctx->nr_errors > 0) {
177 Jmsg(jcr, M_WARNING, 0, _("Had %ld acl errors while doing backup\n"),
178 jcr->acl_ctx->nr_errors);
182 if (jcr->xattr_ctx->nr_errors > 0) {
183 Jmsg(jcr, M_WARNING, 0, _("Had %ld xattr errors while doing backup\n"),
184 jcr->xattr_ctx->nr_errors);
187 /* Delete or keep snapshots */
188 close_snapshot_backup_session(jcr);
189 close_vss_backup_session(jcr);
191 accurate_finish(jcr); /* send deleted or base file list to SD */
193 stop_heartbeat_monitor(jcr);
195 sd->signal(BNET_EOD); /* end of sending data */
200 free_and_null_pool_memory(jcr->acl_ctx->content);
201 bfree_and_null(jcr->acl_ctx);
205 if (jcr->xattr_ctx) {
206 free_and_null_pool_memory(jcr->xattr_ctx->content);
207 bfree_and_null(jcr->xattr_ctx);
211 bfree_and_null(jcr->big_buf);
213 if (jcr->compress_buf) {
214 free_and_null_pool_memory(jcr->compress_buf);
216 if (jcr->pZLIB_compress_workset) {
217 /* Free the zlib stream */
219 deflateEnd((z_stream *)jcr->pZLIB_compress_workset);
221 bfree_and_null(jcr->pZLIB_compress_workset);
223 if (jcr->LZO_compress_workset) {
224 bfree_and_null(jcr->LZO_compress_workset);
227 crypto_session_end(jcr);
230 Dmsg1(100, "end blast_data ok=%d\n", ok);
236 * Called here by find() for each file included.
237 * This is a callback. The original is find_files() above.
239 * Send the file and its data to the Storage daemon.
243 * -1 to ignore file/directory (not used here)
245 int save_file(JCR *jcr, FF_PKT *ff_pkt, bool top_level)
247 bool do_read = false;
248 bool plugin_started = false;
249 bool do_plugin_set = false;
252 bool has_file_data = false;
253 struct save_pkt sp; /* used by option plugin */
254 BSOCK *sd = jcr->store_bsock;
255 bctx_t bctx; /* backup context */
257 memset(&bctx, 0, sizeof(bctx));
259 bctx.ff_pkt = ff_pkt;
263 time_t now = time(NULL);
264 if (jcr->last_stat_time == 0) {
265 jcr->last_stat_time = now;
266 jcr->stat_interval = 30; /* Default 30 seconds */
267 } else if (now >= jcr->last_stat_time + jcr->stat_interval) {
268 jcr->dir_bsock->fsend("Progress Job=x files=%ld bytes=%lld bps=%ld\n",
269 jcr->JobFiles, jcr->JobBytes, jcr->LastRate);
270 jcr->last_stat_time = now;
273 if (jcr->is_canceled() || jcr->is_incomplete()) {
274 Dmsg0(100, "Job canceled by user or marked incomplete.\n");
278 jcr->num_files_examined++; /* bump total file count */
280 switch (ff_pkt->type) {
281 case FT_LNKSAVED: /* Hard linked, file already saved */
282 Dmsg2(130, "FT_LNKSAVED hard link: %s => %s\n", ff_pkt->fname, ff_pkt->link);
285 Dmsg1(130, "FT_REGE saving: %s\n", ff_pkt->fname);
286 has_file_data = true;
289 Dmsg1(130, "FT_REG saving: %s\n", ff_pkt->fname);
290 has_file_data = true;
293 Dmsg2(130, "FT_LNK saving: %s -> %s\n", ff_pkt->fname, ff_pkt->link);
295 case FT_RESTORE_FIRST:
296 Dmsg1(100, "FT_RESTORE_FIRST saving: %s\n", ff_pkt->fname);
298 case FT_PLUGIN_CONFIG:
299 Dmsg1(100, "FT_PLUGIN_CONFIG saving: %s\n", ff_pkt->fname);
302 jcr->num_files_examined--; /* correct file count */
303 return 1; /* not used */
305 Jmsg(jcr, M_INFO, 1, _(" Recursion turned off. Will not descend from %s into %s\n"),
306 ff_pkt->top_fname, ff_pkt->fname);
307 ff_pkt->type = FT_DIREND; /* Backup only the directory entry */
310 /* Suppress message for /dev filesystems */
311 if (!is_in_fileset(ff_pkt)) {
312 Jmsg(jcr, M_INFO, 1, _(" %s is a different filesystem. Will not descend from %s into it.\n"),
313 ff_pkt->fname, ff_pkt->top_fname);
315 ff_pkt->type = FT_DIREND; /* Backup only the directory entry */
318 Jmsg(jcr, M_INFO, 1, _(" Disallowed filesystem. Will not descend from %s into %s\n"),
319 ff_pkt->top_fname, ff_pkt->fname);
320 ff_pkt->type = FT_DIREND; /* Backup only the directory entry */
323 Jmsg(jcr, M_INFO, 1, _(" Disallowed drive type. Will not descend into %s\n"),
329 Dmsg1(130, "FT_DIREND: %s\n", ff_pkt->link);
332 Dmsg1(130, "FT_SPEC saving: %s\n", ff_pkt->fname);
333 if (S_ISSOCK(ff_pkt->statp.st_mode)) {
334 Jmsg(jcr, M_SKIPPED, 1, _(" Socket file skipped: %s\n"), ff_pkt->fname);
339 Dmsg1(130, "FT_RAW saving: %s\n", ff_pkt->fname);
340 has_file_data = true;
343 Dmsg1(130, "FT_FIFO saving: %s\n", ff_pkt->fname);
347 Jmsg(jcr, M_NOTSAVED, 0, _(" Could not access \"%s\": ERR=%s\n"), ff_pkt->fname,
348 be.bstrerror(ff_pkt->ff_errno));
354 Jmsg(jcr, M_NOTSAVED, 0, _(" Could not follow link \"%s\": ERR=%s\n"),
355 ff_pkt->fname, be.bstrerror(ff_pkt->ff_errno));
361 Jmsg(jcr, M_NOTSAVED, 0, _(" Could not stat \"%s\": ERR=%s\n"), ff_pkt->fname,
362 be.bstrerror(ff_pkt->ff_errno));
368 Jmsg(jcr, M_SKIPPED, 1, _(" Unchanged file skipped: %s\n"), ff_pkt->fname);
371 Jmsg(jcr, M_NOTSAVED, 0, _(" Archive file not saved: %s\n"), ff_pkt->fname);
375 Jmsg(jcr, M_NOTSAVED, 0, _(" Could not open directory \"%s\": ERR=%s\n"),
376 ff_pkt->fname, be.bstrerror(ff_pkt->ff_errno));
381 Dmsg1(130, "FT_DELETED: %s\n", ff_pkt->fname);
384 Jmsg(jcr, M_NOTSAVED, 0, _(" Unknown file type %d; not saved: %s\n"),
385 ff_pkt->type, ff_pkt->fname);
390 Dmsg1(130, "bfiled: sending %s to stored\n", ff_pkt->fname);
392 /** Digests and encryption are only useful if there's file data */
393 if (has_file_data && !crypto_setup_digests(bctx)) {
397 /** Initialize the file descriptor we use for data and other streams. */
399 if (ff_pkt->flags & FO_PORTABLE) {
400 set_portable_backup(&ff_pkt->bfd); /* disable Win32 BackupRead() */
403 if (ff_pkt->cmd_plugin) {
404 do_plugin_set = true;
406 /* option and cmd plugin are not compatible together */
407 } else if (ff_pkt->opt_plugin) {
409 /* ask the option plugin what to do with this file */
410 switch (plugin_option_handle_file(jcr, ff_pkt, &sp)) {
412 Dmsg2(10, "Option plugin %s will be used to backup %s\n",
413 ff_pkt->plugin, ff_pkt->fname);
414 do_plugin_set = true;
417 Dmsg2(10, "Option plugin %s decided to skip %s\n",
418 ff_pkt->plugin, ff_pkt->fname);
421 Dmsg2(10, "Option plugin %s decided to let bacula handle %s\n",
422 ff_pkt->plugin, ff_pkt->fname);
428 /* Tell bfile that it needs to call plugin */
429 if (!set_cmd_plugin(&ff_pkt->bfd, jcr)) {
432 send_plugin_name(jcr, sd, true); /* signal start of plugin data */
433 plugin_started = true;
436 /** Send attributes -- must be done after binit() */
437 if (!encode_and_send_attributes(bctx)) {
440 /** Meta data only for restore object */
441 if (IS_FT_OBJECT(ff_pkt->type)) {
444 /** Meta data only for deleted files */
445 if (ff_pkt->type == FT_DELETED) {
448 /** Set up the encryption context and send the session data to the SD */
449 if (has_file_data && jcr->crypto.pki_encrypt) {
450 if (!crypto_session_send(jcr, sd)) {
456 * Open any file with data that we intend to save, then save it.
458 * Note, if is_win32_backup, we must open the Directory so that
459 * the BackupRead will save its permissions and ownership streams.
461 if (ff_pkt->type != FT_LNKSAVED && S_ISREG(ff_pkt->statp.st_mode)) {
463 do_read = !is_portable_backup(&ff_pkt->bfd) || ff_pkt->statp.st_size > 0;
465 do_read = ff_pkt->statp.st_size > 0;
467 } else if (ff_pkt->type == FT_RAW || ff_pkt->type == FT_FIFO ||
468 ff_pkt->type == FT_REPARSE || ff_pkt->type == FT_JUNCTION ||
469 (!is_portable_backup(&ff_pkt->bfd) && ff_pkt->type == FT_DIREND)) {
473 if (ff_pkt->cmd_plugin && !ff_pkt->no_read) {
477 Dmsg2(150, "type=%d do_read=%d\n", ff_pkt->type, do_read);
481 if (ff_pkt->type == FT_FIFO) {
482 tid = start_thread_timer(jcr, pthread_self(), 60);
486 int noatime = ff_pkt->flags & FO_NOATIME ? O_NOATIME : 0;
487 ff_pkt->bfd.reparse_point = (ff_pkt->type == FT_REPARSE ||
488 ff_pkt->type == FT_JUNCTION);
489 set_fattrs(&ff_pkt->bfd, &ff_pkt->statp);
490 if (bopen(&ff_pkt->bfd, ff_pkt->fname, O_RDONLY | O_BINARY | noatime, 0) < 0) {
491 ff_pkt->ff_errno = errno;
493 Jmsg(jcr, M_NOTSAVED, 0, _(" Cannot open \"%s\": ERR=%s.\n"), ff_pkt->fname,
497 stop_thread_timer(tid);
503 stop_thread_timer(tid);
507 stat = send_data(bctx, bctx.data_stream);
509 if (ff_pkt->flags & FO_CHKCHANGES) {
510 has_file_changed(jcr, ff_pkt);
513 bclose(&ff_pkt->bfd);
520 #ifdef HAVE_DARWIN_OS
521 if (!send_resource_fork(bctx)) {
527 * Save ACLs when requested and available for anything not being a symlink
528 * and not being a plugin.
531 if (!backup_acl_streams(jcr, ff_pkt)) {
537 * Save Extended Attributes when requested and available for all files not
541 if (!backup_xattr_streams(jcr, ff_pkt)) {
546 if (!crypto_terminate_digests(bctx)) {
554 if (jcr->is_incomplete() || jcr->is_canceled()) {
555 Dmsg0(100, "Job canceled by user or marked incomplete.\n");
558 if (plugin_started) {
559 send_plugin_name(jcr, sd, false); /* signal end of plugin data */
561 if (ff_pkt->opt_plugin) {
562 jcr->plugin_sp = NULL; /* sp is local to this function */
563 jcr->plugin_ctx = NULL;
565 jcr->opt_plugin = false;
572 * Send data read from an already open file descriptor.
574 * We return 1 on success and 0 on errors.
577 * We use ff_pkt->statp.st_size when FO_SPARSE to know when to stop
579 * Currently this is not a problem as the only other stream, resource forks,
580 * are not handled as sparse files.
582 static int send_data(bctx_t &bctx, int stream)
585 BSOCK *sd = jcr->store_bsock;
587 #ifdef FD_NO_SEND_TEST
591 bctx.rsize = jcr->buf_size;
593 bctx.cipher_ctx = NULL;
594 bctx.msgsave = sd->msg;
595 bctx.rbuf = sd->msg; /* read buffer */
596 bctx.wbuf = sd->msg; /* write buffer */
597 bctx.cipher_input = (uint8_t *)bctx.rbuf; /* encrypt uncompressed data */
599 Dmsg1(300, "Saving data, type=%d\n", bctx.ff_pkt->type);
601 if (!setup_compression(bctx)) {
605 if (bctx.ff_pkt->flags & FO_ENCRYPT && !crypto_allocate_ctx(bctx)) {
610 * Send Data header to Storage daemon
611 * <file-index> <stream> <expected stream length>
613 if (!sd->fsend("%ld %d %lld", jcr->JobFiles, stream,
614 (int64_t)bctx.ff_pkt->statp.st_size)) {
615 if (!jcr->is_job_canceled()) {
616 Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
621 Dmsg1(300, ">stored: datahdr %s\n", sd->msg);
624 * Make space at beginning of buffer for fileAddr because this
625 * same buffer will be used for writing if compression is off.
627 if ((bctx.ff_pkt->flags & FO_SPARSE) || (bctx.ff_pkt->flags & FO_OFFSETS)) {
628 bctx.rbuf += OFFSET_FADDR_SIZE;
629 bctx.rsize -= OFFSET_FADDR_SIZE;
630 #if defined(HAVE_FREEBSD_OS) || defined(__FreeBSD_kernel__)
632 * To read FreeBSD partitions, the read size must be
635 bctx.rsize = (bctx.rsize/512) * 512;
639 /** a RAW device read on win32 only works if the buffer is a multiple of 512 */
641 if (S_ISBLK(bctx.ff_pkt->statp.st_mode)) {
642 bctx.rsize = (bctx.rsize/512) * 512;
644 Dmsg1(200, "Fattrs=0X%x\n", bctx.ff_pkt->bfd.fattrs);
645 if (bctx.ff_pkt->bfd.fattrs & FILE_ATTRIBUTE_ENCRYPTED) {
646 if (!p_ReadEncryptedFileRaw) {
647 Jmsg0(bctx.jcr, M_FATAL, 0, _("Windows Encrypted data not supported on this OS.\n"));
650 /* This single call reads all EFS data delivers it to a callback */
651 if (p_ReadEncryptedFileRaw((PFE_EXPORT_FUNC)read_efs_data_cb, &bctx,
652 bctx.ff_pkt->bfd.pvContext) != 0) {
655 /* All read, so skip to finish sending */
658 /* Fall through to standard bread() loop */
662 * Normal read the file data in a loop and send it to SD
664 while ((sd->msglen=(uint32_t)bread(&bctx.ff_pkt->bfd, bctx.rbuf, bctx.rsize)) > 0) {
665 if (!process_and_send_data(bctx)) {
668 } /* end while read file data */
672 if (sd->msglen < 0) { /* error */
674 Jmsg(jcr, M_ERROR, 0, _("Read error on file %s. ERR=%s\n"),
675 bctx.ff_pkt->fname, be.bstrerror(bctx.ff_pkt->bfd.berrno));
676 if (jcr->JobErrors++ > 1000) { /* insanity check */
677 Jmsg(jcr, M_FATAL, 0, _("Too many errors. JobErrors=%d.\n"), jcr->JobErrors);
679 } else if (bctx.ff_pkt->flags & FO_ENCRYPT) {
681 * For encryption, we must call finalize to push out any
684 if (!crypto_cipher_finalize(bctx.cipher_ctx, (uint8_t *)jcr->crypto.crypto_buf,
685 &bctx.encrypted_len)) {
686 /* Padding failed. Shouldn't happen. */
687 Jmsg(jcr, M_FATAL, 0, _("Encryption padding error\n"));
691 /** Note, on SSL pre-0.9.7, there is always some output */
692 if (bctx.encrypted_len > 0) {
693 sd->msglen = bctx.encrypted_len; /* set encrypted length */
694 sd->msg = jcr->crypto.crypto_buf; /* set correct write buffer */
696 if (!jcr->is_job_canceled()) {
697 Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
702 Dmsg1(130, "Send data to SD len=%d\n", sd->msglen);
703 jcr->JobBytes += sd->msglen; /* count bytes saved possibly compressed/encrypted */
704 sd->msg = bctx.msgsave; /* restore bnet buffer */
709 if (!sd->signal(BNET_EOD)) { /* indicate end of file data */
710 if (!jcr->is_job_canceled()) {
711 Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
717 /** Free the cipher context */
718 if (bctx.cipher_ctx) {
719 crypto_cipher_free(bctx.cipher_ctx);
724 /** Free the cipher context */
725 if (bctx.cipher_ctx) {
726 crypto_cipher_free(bctx.cipher_ctx);
729 sd->msg = bctx.msgsave; /* restore bnet buffer */
736 * Apply processing (sparse, compression, encryption, and
739 bool process_and_send_data(bctx_t &bctx)
744 /** Check for sparse blocks */
745 if (bctx.ff_pkt->flags & FO_SPARSE) {
747 bool allZeros = false;
748 if ((sd->msglen == bctx.rsize &&
749 bctx.fileAddr+sd->msglen < (uint64_t)bctx.ff_pkt->statp.st_size) ||
750 ((bctx.ff_pkt->type == FT_RAW || bctx.ff_pkt->type == FT_FIFO) &&
751 (uint64_t)bctx.ff_pkt->statp.st_size == 0)) {
752 allZeros = is_buf_zero(bctx.rbuf, bctx.rsize);
755 /** Put file address as first data in buffer */
756 ser_begin(bctx.wbuf, OFFSET_FADDR_SIZE);
757 ser_uint64(bctx.fileAddr); /* store fileAddr in begin of buffer */
759 bctx.fileAddr += sd->msglen; /* update file address */
760 /** Skip block of all zeros */
762 return true; /* skip block of zeros */
764 } else if (bctx.ff_pkt->flags & FO_OFFSETS) {
766 ser_begin(bctx.wbuf, OFFSET_FADDR_SIZE);
767 ser_uint64(bctx.ff_pkt->bfd.offset); /* store offset in begin of buffer */
770 jcr->ReadBytes += sd->msglen; /* count bytes read */
772 /** Uncompressed cipher input length */
773 bctx.cipher_input_len = sd->msglen;
775 /** Update checksum if requested */
777 crypto_digest_update(bctx.digest, (uint8_t *)bctx.rbuf, sd->msglen);
780 /** Update signing digest if requested */
781 if (bctx.signing_digest) {
782 crypto_digest_update(bctx.signing_digest, (uint8_t *)bctx.rbuf, sd->msglen);
785 if (have_libz && !do_libz_compression(bctx)) {
789 if (have_lzo && !do_lzo_compression(bctx)) {
794 * Note, here we prepend the current record length to the beginning
795 * of the encrypted data. This is because both sparse and compression
796 * restore handling want records returned to them with exactly the
797 * same number of bytes that were processed in the backup handling.
798 * That is, both are block filters rather than a stream. When doing
799 * compression, the compression routines may buffer data, so that for
800 * any one record compressed, when it is decompressed the same size
801 * will not be obtained. Of course, the buffered data eventually comes
802 * out in subsequent crypto_cipher_update() calls or at least
803 * when crypto_cipher_finalize() is called. Unfortunately, this
804 * "feature" of encryption enormously complicates the restore code.
806 if (bctx.ff_pkt->flags & FO_ENCRYPT) {
807 uint32_t initial_len = 0;
810 if ((bctx.ff_pkt->flags & FO_SPARSE) || (bctx.ff_pkt->flags & FO_OFFSETS)) {
811 bctx.cipher_input_len += OFFSET_FADDR_SIZE;
814 /** Encrypt the length of the input block */
815 uint8_t packet_len[sizeof(uint32_t)];
817 ser_begin(packet_len, sizeof(uint32_t));
818 ser_uint32(bctx.cipher_input_len); /* store data len in begin of buffer */
819 Dmsg1(20, "Encrypt len=%d\n", bctx.cipher_input_len);
821 if (!crypto_cipher_update(bctx.cipher_ctx, packet_len, sizeof(packet_len),
822 (uint8_t *)jcr->crypto.crypto_buf, &initial_len)) {
823 /** Encryption failed. Shouldn't happen. */
824 Jmsg(jcr, M_FATAL, 0, _("Encryption error\n"));
828 /** Encrypt the input block */
829 if (crypto_cipher_update(bctx.cipher_ctx, bctx.cipher_input, bctx.cipher_input_len,
830 (uint8_t *)&jcr->crypto.crypto_buf[initial_len], &bctx.encrypted_len)) {
831 if ((initial_len + bctx.encrypted_len) == 0) {
832 /** No full block of data available, read more data */
835 Dmsg2(400, "encrypted len=%d unencrypted len=%d\n", bctx.encrypted_len,
837 sd->msglen = initial_len + bctx.encrypted_len; /* set encrypted length */
839 /** Encryption failed. Shouldn't happen. */
840 Jmsg(jcr, M_FATAL, 0, _("Encryption error\n"));
845 /* Send the buffer to the Storage daemon */
846 if ((bctx.ff_pkt->flags & FO_SPARSE) || (bctx.ff_pkt->flags & FO_OFFSETS)) {
847 sd->msglen += OFFSET_FADDR_SIZE; /* include fileAddr in size */
849 sd->msg = bctx.wbuf; /* set correct write buffer */
851 if (!jcr->is_job_canceled()) {
852 Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
857 Dmsg1(130, "Send data to SD len=%d\n", sd->msglen);
859 jcr->JobBytes += sd->msglen; /* count bytes saved possibly compressed/encrypted */
860 sd->msg = bctx.msgsave; /* restore read buffer */
867 bool encode_and_send_attributes(bctx_t &bctx)
869 BSOCK *sd = bctx.jcr->store_bsock;
871 FF_PKT *ff_pkt = bctx.ff_pkt;
872 char attribs[MAXSTRING];
873 char attribsExBuf[MAXSTRING];
874 char *attribsEx = NULL;
878 int hangup = get_hangup();
879 int blowup = get_blowup();
880 #ifdef FD_NO_SEND_TEST
884 Dmsg1(300, "encode_and_send_attrs fname=%s\n", ff_pkt->fname);
885 /** Find what data stream we will use, then encode the attributes */
886 if ((bctx.data_stream = select_data_stream(ff_pkt)) == STREAM_NONE) {
887 /* This should not happen */
888 Jmsg0(jcr, M_FATAL, 0, _("Invalid file flags, no supported data stream type.\n"));
891 encode_stat(attribs, &ff_pkt->statp, sizeof(ff_pkt->statp), ff_pkt->LinkFI, bctx.data_stream);
893 /** Now possibly extend the attributes */
894 if (IS_FT_OBJECT(ff_pkt->type)) {
895 attr_stream = STREAM_RESTORE_OBJECT;
897 attribsEx = attribsExBuf;
898 attr_stream = encode_attribsEx(jcr, attribsEx, ff_pkt);
901 Dmsg3(300, "File %s\nattribs=%s\nattribsEx=%s\n", ff_pkt->fname, attribs, attribsEx);
904 jcr->JobFiles++; /* increment number of files sent */
905 ff_pkt->FileIndex = jcr->JobFiles; /* return FileIndex */
906 pm_strcpy(jcr->last_fname, ff_pkt->fname);
909 /* Debug code: check if we must hangup */
910 if (hangup > 0 && (jcr->JobFiles > (uint32_t)hangup)) {
911 jcr->setJobStatus(JS_Incomplete);
912 Jmsg1(jcr, M_FATAL, 0, "Debug hangup requested after %d files.\n", hangup);
917 if (blowup > 0 && (jcr->JobFiles > (uint32_t)blowup)) {
918 Jmsg1(jcr, M_ABORT, 0, "Debug blowup requested after %d files.\n", blowup);
923 * Send Attributes header to Storage daemon
924 * <file-index> <stream> <info>
926 if (!sd->fsend("%ld %d 0", jcr->JobFiles, attr_stream)) {
927 if (!jcr->is_canceled() && !jcr->is_incomplete()) {
928 Jmsg2(jcr, M_FATAL, 0, _("Network send error to SD. Data=%s ERR=%s\n"),
929 sd->msg, sd->bstrerror());
933 Dmsg1(300, ">stored: attrhdr %s\n", sd->msg);
936 * Send file attributes to Storage daemon
939 * Filename (full path)
941 * Link name (if type==FT_LNK or FT_LNKSAVED)
942 * Encoded extended-attributes (for Win32)
944 * or send Restore Object to Storage daemon
948 * Object_len (possibly compressed)
949 * Object_full_len (not compressed)
955 * For a directory, link is the same as fname, but with trailing
956 * slash. For a linked file, link is the link.
958 if (!IS_FT_OBJECT(ff_pkt->type) && ff_pkt->type != FT_DELETED) { /* already stripped */
961 switch (ff_pkt->type) {
964 Dmsg3(300, "Link %d %s to %s\n", jcr->JobFiles, ff_pkt->fname, ff_pkt->link);
965 stat = sd->fsend("%ld %d %s%c%s%c%s%c%s%c%u%c", jcr->JobFiles,
966 ff_pkt->type, ff_pkt->fname, 0, attribs, 0,
967 ff_pkt->link, 0, attribsEx, 0, ff_pkt->delta_seq, 0);
972 /* Here link is the canonical filename (i.e. with trailing slash) */
973 stat = sd->fsend("%ld %d %s%c%s%c%c%s%c%u%c", jcr->JobFiles,
974 ff_pkt->type, ff_pkt->link, 0, attribs, 0, 0,
975 attribsEx, 0, ff_pkt->delta_seq, 0);
977 case FT_PLUGIN_CONFIG:
978 case FT_RESTORE_FIRST:
979 comp_len = ff_pkt->object_len;
980 ff_pkt->object_compression = 0;
981 if (ff_pkt->object_len > 1000) {
982 /* Big object, compress it */
983 comp_len = ff_pkt->object_len + 1000;
984 POOLMEM *comp_obj = get_memory(comp_len);
985 /* *** FIXME *** check Zdeflate error */
986 Zdeflate(ff_pkt->object, ff_pkt->object_len, comp_obj, comp_len);
987 if (comp_len < ff_pkt->object_len) {
988 ff_pkt->object = comp_obj;
989 ff_pkt->object_compression = 1; /* zlib level 9 compression */
991 /* Uncompressed object smaller, use it */
992 comp_len = ff_pkt->object_len;
994 Dmsg2(100, "Object compressed from %d to %d bytes\n", ff_pkt->object_len, comp_len);
996 sd->msglen = Mmsg(sd->msg, "%d %d %d %d %d %d %s%c%s%c",
997 jcr->JobFiles, ff_pkt->type, ff_pkt->object_index,
998 comp_len, ff_pkt->object_len, ff_pkt->object_compression,
999 ff_pkt->fname, 0, ff_pkt->object_name, 0);
1000 sd->msg = check_pool_memory_size(sd->msg, sd->msglen + comp_len + 2);
1001 memcpy(sd->msg + sd->msglen, ff_pkt->object, comp_len);
1002 /* Note we send one extra byte so Dir can store zero after object */
1003 sd->msglen += comp_len + 1;
1005 if (ff_pkt->object_compression) {
1006 free_and_null_pool_memory(ff_pkt->object);
1010 stat = sd->fsend("%ld %d %s%c%s%c%c%s%c%d%c", jcr->JobFiles,
1011 ff_pkt->type, ff_pkt->fname, 0, attribs, 0, 0, attribsEx, 0,
1012 ff_pkt->delta_seq, 0);
1015 stat = sd->fsend("%ld %d %s%c%s%c%c%s%c%u%c", jcr->JobFiles,
1016 ff_pkt->type, ff_pkt->fname, 0, attribs, 0, 0,
1017 attribsEx, 0, ff_pkt->delta_seq, 0);
1021 if (!IS_FT_OBJECT(ff_pkt->type) && ff_pkt->type != FT_DELETED) {
1022 unstrip_path(ff_pkt);
1025 Dmsg2(300, ">stored: attr len=%d: %s\n", sd->msglen, sd->msg);
1026 if (!stat && !jcr->is_job_canceled()) {
1027 Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
1030 sd->signal(BNET_EOD); /* indicate end of attributes data */
1035 * Setup bctx for doing compression
1037 static bool setup_compression(bctx_t &bctx)
1039 JCR *jcr = bctx.jcr;
1041 #if defined(HAVE_LIBZ) || defined(HAVE_LZO)
1042 bctx.compress_len = 0;
1043 bctx.max_compress_len = 0;
1048 if ((bctx.ff_pkt->flags & FO_COMPRESS) && bctx.ff_pkt->Compress_algo == COMPRESS_GZIP) {
1049 if ((bctx.ff_pkt->flags & FO_SPARSE) || (bctx.ff_pkt->flags & FO_OFFSETS)) {
1050 bctx.cbuf = (Bytef *)jcr->compress_buf + OFFSET_FADDR_SIZE;
1051 bctx.max_compress_len = jcr->compress_buf_size - OFFSET_FADDR_SIZE;
1053 bctx.cbuf = (Bytef *)jcr->compress_buf;
1054 bctx.max_compress_len = jcr->compress_buf_size; /* set max length */
1056 bctx.wbuf = jcr->compress_buf; /* compressed output here */
1057 bctx.cipher_input = (uint8_t *)jcr->compress_buf; /* encrypt compressed data */
1060 * Only change zlib parameters if there is no pending operation.
1061 * This should never happen as deflatereset is called after each
1065 if (((z_stream*)jcr->pZLIB_compress_workset)->total_in == 0) {
1066 /** set gzip compression level - must be done per file */
1067 if ((zstat=deflateParams((z_stream*)jcr->pZLIB_compress_workset,
1068 bctx.ff_pkt->Compress_level, Z_DEFAULT_STRATEGY)) != Z_OK) {
1069 Jmsg(jcr, M_FATAL, 0, _("Compression deflateParams error: %d\n"), zstat);
1070 jcr->setJobStatus(JS_ErrorTerminated);
1077 memset(&bctx.ch, 0, sizeof(comp_stream_header));
1080 if ((bctx.ff_pkt->flags & FO_COMPRESS) && bctx.ff_pkt->Compress_algo == COMPRESS_LZO1X) {
1081 if ((bctx.ff_pkt->flags & FO_SPARSE) || (bctx.ff_pkt->flags & FO_OFFSETS)) {
1082 bctx.cbuf = (Bytef *)jcr->compress_buf + OFFSET_FADDR_SIZE;
1083 bctx.cbuf2 = (Bytef *)jcr->compress_buf + OFFSET_FADDR_SIZE + sizeof(comp_stream_header);
1084 bctx.max_compress_len = jcr->compress_buf_size - OFFSET_FADDR_SIZE;
1086 bctx.cbuf = (Bytef *)jcr->compress_buf;
1087 bctx.cbuf2 = (Bytef *)jcr->compress_buf + sizeof(comp_stream_header);
1088 bctx.max_compress_len = jcr->compress_buf_size; /* set max length */
1090 bctx.ch.magic = COMPRESS_LZO1X;
1091 bctx.ch.version = COMP_HEAD_VERSION;
1092 bctx.wbuf = jcr->compress_buf; /* compressed output here */
1093 bctx.cipher_input = (uint8_t *)jcr->compress_buf; /* encrypt compressed data */
1097 bctx.max_compress_len = 0;
1103 * Send MacOS resource fork to SD
1105 #ifdef HAVE_DARWIN_OS
1106 static bool send_resource_fork(bctx_t &bctx)
1108 FF_PKT *ff_pkt = bctx.ff_pkt;
1109 JCR *jcr = bctx.jcr;
1110 BSOCK *sd = bctx.sd;
1113 /** Regular files can have resource forks and Finder Info */
1114 if (ff_pkt->type != FT_LNKSAVED && (S_ISREG(ff_pkt->statp.st_mode) &&
1115 ff_pkt->flags & FO_HFSPLUS)) {
1116 if (ff_pkt->hfsinfo.rsrclength > 0) {
1119 if (bopen_rsrc(&ff_pkt->bfd, ff_pkt->fname, O_RDONLY | O_BINARY, 0) < 0) {
1120 ff_pkt->ff_errno = errno;
1122 Jmsg(jcr, M_NOTSAVED, -1, _(" Cannot open resource fork for \"%s\": ERR=%s.\n"),
1123 ff_pkt->fname, be.bstrerror());
1125 if (is_bopen(&ff_pkt->bfd)) {
1126 bclose(&ff_pkt->bfd);
1130 flags = ff_pkt->flags;
1131 ff_pkt->flags &= ~(FO_COMPRESS|FO_SPARSE|FO_OFFSETS);
1132 if (flags & FO_ENCRYPT) {
1133 rsrc_stream = STREAM_ENCRYPTED_MACOS_FORK_DATA;
1135 rsrc_stream = STREAM_MACOS_FORK_DATA;
1137 stat = send_data(bctx, rsrc_stream);
1138 ff_pkt->flags = flags;
1139 bclose(&ff_pkt->bfd);
1145 Dmsg1(300, "Saving Finder Info for \"%s\"\n", ff_pkt->fname);
1146 sd->fsend("%ld %d 0", jcr->JobFiles, STREAM_HFSPLUS_ATTRIBUTES);
1147 Dmsg1(300, "bfiled>stored:header %s\n", sd->msg);
1148 pm_memcpy(sd->msg, ff_pkt->hfsinfo.fndrinfo, 32);
1151 crypto_digest_update(bctx.digest, (uint8_t *)sd->msg, sd->msglen);
1153 if (bctx.signing_digest) {
1154 crypto_digest_update(bctx.signing_digest, (uint8_t *)sd->msg, sd->msglen);
1157 sd->signal(BNET_EOD);
1163 static bool do_libz_compression(bctx_t &bctx)
1166 JCR *jcr = bctx.jcr;
1167 BSOCK *sd = bctx.sd;
1170 /** Do compression if turned on */
1171 if (bctx.ff_pkt->flags & FO_COMPRESS && bctx.ff_pkt->Compress_algo == COMPRESS_GZIP && jcr->pZLIB_compress_workset) {
1172 Dmsg3(400, "cbuf=0x%x rbuf=0x%x len=%u\n", bctx.cbuf, bctx.rbuf, sd->msglen);
1174 ((z_stream*)jcr->pZLIB_compress_workset)->next_in = (Bytef *)bctx.rbuf;
1175 ((z_stream*)jcr->pZLIB_compress_workset)->avail_in = sd->msglen;
1176 ((z_stream*)jcr->pZLIB_compress_workset)->next_out = bctx.cbuf;
1177 ((z_stream*)jcr->pZLIB_compress_workset)->avail_out = bctx.max_compress_len;
1179 if ((zstat=deflate((z_stream*)jcr->pZLIB_compress_workset, Z_FINISH)) != Z_STREAM_END) {
1180 Jmsg(jcr, M_FATAL, 0, _("Compression deflate error: %d\n"), zstat);
1181 jcr->setJobStatus(JS_ErrorTerminated);
1184 bctx.compress_len = ((z_stream*)jcr->pZLIB_compress_workset)->total_out;
1185 /** reset zlib stream to be able to begin from scratch again */
1186 if ((zstat=deflateReset((z_stream*)jcr->pZLIB_compress_workset)) != Z_OK) {
1187 Jmsg(jcr, M_FATAL, 0, _("Compression deflateReset error: %d\n"), zstat);
1188 jcr->setJobStatus(JS_ErrorTerminated);
1192 Dmsg2(400, "GZIP compressed len=%d uncompressed len=%d\n", bctx.compress_len,
1195 sd->msglen = bctx.compress_len; /* set compressed length */
1196 bctx.cipher_input_len = bctx.compress_len;
1202 static bool do_lzo_compression(bctx_t &bctx)
1205 JCR *jcr = bctx.jcr;
1206 BSOCK *sd = bctx.sd;
1209 /** Do compression if turned on */
1210 if (bctx.ff_pkt->flags & FO_COMPRESS && bctx.ff_pkt->Compress_algo == COMPRESS_LZO1X && jcr->LZO_compress_workset) {
1211 lzo_uint len; /* TODO: See with the latest patch how to handle lzo_uint with 64bit */
1214 ser_begin(bctx.cbuf, sizeof(comp_stream_header));
1216 Dmsg3(400, "cbuf=0x%x rbuf=0x%x len=%u\n", bctx.cbuf, bctx.rbuf, sd->msglen);
1218 lzores = lzo1x_1_compress((const unsigned char*)bctx.rbuf, sd->msglen, bctx.cbuf2,
1219 &len, jcr->LZO_compress_workset);
1220 bctx.compress_len = len;
1221 if (lzores == LZO_E_OK && bctx.compress_len <= bctx.max_compress_len) {
1222 /* complete header */
1223 ser_uint32(COMPRESS_LZO1X);
1224 ser_uint32(bctx.compress_len);
1225 ser_uint16(bctx.ch.level);
1226 ser_uint16(bctx.ch.version);
1228 /** this should NEVER happen */
1229 Jmsg(jcr, M_FATAL, 0, _("Compression LZO error: %d\n"), lzores);
1230 jcr->setJobStatus(JS_ErrorTerminated);
1234 Dmsg2(400, "LZO compressed len=%d uncompressed len=%d\n", bctx.compress_len,
1237 bctx.compress_len += sizeof(comp_stream_header); /* add size of header */
1238 sd->msglen = bctx.compress_len; /* set compressed length */
1239 bctx.cipher_input_len = bctx.compress_len;
1246 * Do in place strip of path
1248 static bool do_snap_strip(FF_PKT *ff)
1250 /* if the string starts with the snapshot path name, we can replace
1251 * by the volume name. The volume_path is smaller than the snapshot_path
1252 * snapshot_path = volume_path + /.snapshots/job-xxxx
1254 ASSERT(strlen(ff->snapshot_path) > strlen(ff->volume_path));
1255 int sp_first = strlen(ff->snapshot_path); /* point after snapshot_path in fname */
1256 if (strncmp(ff->fname, ff->snapshot_path, sp_first) == 0) {
1257 int last = pm_strcpy(ff->snap_fname, ff->volume_path);
1258 last = MAX(last - 1, 0);
1260 if (ff->snap_fname[last] == '/') {
1261 if (ff->fname[sp_first] == '/') { /* compare with the first character of the string (sp_first not sp_first-1) */
1262 ff->snap_fname[last] = 0;
1265 if (ff->fname[sp_first] != '/') {
1266 pm_strcat(ff->snap_fname, "/");
1270 pm_strcat(ff->snap_fname, ff->fname + sp_first);
1271 ASSERT(strlen(ff->fname) > strlen(ff->snap_fname));
1272 strcpy(ff->fname, ff->snap_fname);
1273 Dmsg2(DT_SNAPSHOT|20, "%s -> %s\n", ff->fname_save, ff->fname);
1275 if (strncmp(ff->link, ff->snapshot_path, sp_first) == 0) {
1276 int last = pm_strcpy(ff->snap_fname, ff->volume_path);
1277 last = MAX(last - 1, 0);
1279 if (ff->snap_fname[last] == '/') {
1280 if (ff->link[sp_first] == '/') { /* compare with the first character of the string (sp_first not sp_first-1) */
1281 ff->snap_fname[last] = 0;
1284 if (ff->link[sp_first] != '/') {
1285 pm_strcat(ff->snap_fname, "/");
1289 pm_strcat(ff->snap_fname, ff->link + sp_first);
1290 ASSERT(strlen(ff->link) > strlen(ff->snap_fname));
1291 strcpy(ff->link, ff->snap_fname);
1292 Dmsg2(DT_SNAPSHOT|20, "%s -> %s\n", ff->link_save, ff->link);
1299 * Do in place strip of path
1301 static bool do_strip(int count, char *in)
1307 /** Copy to first path separator -- Win32 might have c: ... */
1308 while (*in && !IsPathSeparator(*in)) {
1311 if (*in) { /* Not at the end of the string */
1313 numsep++; /* one separator seen */
1315 for (stripped=0; stripped<count && *in; stripped++) {
1316 while (*in && !IsPathSeparator(*in)) {
1317 in++; /* skip chars */
1320 numsep++; /* count separators seen */
1321 in++; /* skip separator */
1325 while (*in) { /* copy to end */
1326 if (IsPathSeparator(*in)) {
1332 Dmsg4(500, "stripped=%d count=%d numsep=%d sep>count=%d\n",
1333 stripped, count, numsep, numsep>count);
1334 return stripped==count && numsep>count;
1338 * If requested strip leading components of the path so that we can
1339 * save file as if it came from a subdirectory. This is most useful
1340 * for dealing with snapshots, by removing the snapshot directory, or
1341 * in handling vendor migrations where files have been restored with
1342 * a vendor product into a subdirectory.
1344 * When we are using snapshots, we might need to convert the path
1345 * back to the original one using the strip_snap_path option.
1347 void strip_path(FF_PKT *ff_pkt)
1349 if (!ff_pkt->strip_snap_path &&
1350 (!(ff_pkt->flags & FO_STRIPPATH) || ff_pkt->strip_path <= 0))
1352 Dmsg1(200, "No strip for %s\n", ff_pkt->fname);
1355 /* shared part between strip and snapshot */
1356 if (!ff_pkt->fname_save) {
1357 ff_pkt->fname_save = get_pool_memory(PM_FNAME);
1358 ff_pkt->link_save = get_pool_memory(PM_FNAME);
1359 *ff_pkt->link_save = 0;
1361 pm_strcpy(ff_pkt->fname_save, ff_pkt->fname);
1362 if (ff_pkt->type != FT_LNK && ff_pkt->fname != ff_pkt->link) {
1363 pm_strcpy(ff_pkt->link_save, ff_pkt->link);
1364 Dmsg2(500, "strcpy link_save=%d link=%d\n", strlen(ff_pkt->link_save),
1365 strlen(ff_pkt->link));
1369 if (ff_pkt->strip_snap_path) {
1370 if (!do_snap_strip(ff_pkt)) {
1371 Dmsg1(0, "Something wrong with do_snap_strip(%s)\n", ff_pkt->fname);
1372 unstrip_path(ff_pkt);
1377 /* See if we want also to strip the path */
1378 if (!(ff_pkt->flags & FO_STRIPPATH) || ff_pkt->strip_path <= 0) {
1383 * Strip path. If it doesn't succeed put it back. If
1384 * it does, and there is a different link string,
1385 * attempt to strip the link. If it fails, back them
1387 * Do not strip symlinks.
1388 * I.e. if either stripping fails don't strip anything.
1390 if (!do_strip(ff_pkt->strip_path, ff_pkt->fname)) {
1391 unstrip_path(ff_pkt);
1394 /** Strip links but not symlinks */
1395 if (ff_pkt->type != FT_LNK && ff_pkt->fname != ff_pkt->link) {
1396 if (!do_strip(ff_pkt->strip_path, ff_pkt->link)) {
1397 unstrip_path(ff_pkt);
1402 Dmsg3(10, "fname=%s stripped=%s link=%s\n", ff_pkt->fname_save, ff_pkt->fname,
1406 void unstrip_path(FF_PKT *ff_pkt)
1408 if (!ff_pkt->strip_snap_path &&
1409 (!(ff_pkt->flags & FO_STRIPPATH) || ff_pkt->strip_path <= 0))
1414 strcpy(ff_pkt->fname, ff_pkt->fname_save);
1415 if (ff_pkt->type != FT_LNK && ff_pkt->fname != ff_pkt->link) {
1416 Dmsg2(10, "strcpy link=%s link_save=%s\n", ff_pkt->link,
1418 strcpy(ff_pkt->link, ff_pkt->link_save);
1419 Dmsg2(10, "strcpy link=%d link_save=%d\n", strlen(ff_pkt->link),
1420 strlen(ff_pkt->link_save));
1425 static void close_vss_backup_session(JCR *jcr)
1427 #if defined(WIN32_VSS)
1428 /* STOP VSS ON WIN32 */
1429 /* tell vss to close the backup session */
1430 if (jcr->Snapshot) {
1431 if (g_pVSSClient->CloseBackup()) {
1432 /* inform user about writer states */
1433 for (int i=0; i<(int)g_pVSSClient->GetWriterCount(); i++) {
1434 int msg_type = M_INFO;
1435 if (g_pVSSClient->GetWriterState(i) < 1) {
1436 msg_type = M_WARNING;
1439 Jmsg(jcr, msg_type, 0, _("VSS Writer (BackupComplete): %s\n"), g_pVSSClient->GetWriterInfo(i));
1442 /* Generate Job global writer metadata */
1443 WCHAR *metadata = g_pVSSClient->GetMetadata();
1445 FF_PKT *ff_pkt = jcr->ff;
1446 ff_pkt->fname = (char *)"*all*"; /* for all plugins */
1447 ff_pkt->type = FT_RESTORE_FIRST;
1449 ff_pkt->object_name = (char *)"job_metadata.xml";
1450 ff_pkt->object = (char *)metadata;
1451 ff_pkt->object_len = (wcslen(metadata) + 1) * sizeof(WCHAR);
1452 ff_pkt->object_index = (int)time(NULL);
1453 save_file(jcr, ff_pkt, true);