2 * Bacula File Daemon backup.c send file attributes and data
3 * to the Storage daemon.
5 * Kern Sibbald, March MM
11 Copyright (C) 2000-2005 Kern Sibbald
13 This program is free software; you can redistribute it and/or
14 modify it under the terms of the GNU General Public License
15 version 2 as amended with additional clauses defined in the
16 file LICENSE in the main source directory.
18 This program is distributed in the hope that it will be useful,
19 but WITHOUT ANY WARRANTY; without even the implied warranty of
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 the file LICENSE for additional details.
28 /* Forward referenced functions */
29 static int save_file(FF_PKT *ff_pkt, void *pkt, bool top_level);
30 static int send_data(JCR *jcr, int stream, FF_PKT *ff_pkt, DIGEST *digest, DIGEST *signature_digest);
31 static bool encode_and_send_attributes(JCR *jcr, FF_PKT *ff_pkt, int &data_stream);
32 static bool read_and_send_acl(JCR *jcr, int acltype, int stream);
35 * Find all the requested files and send them
36 * to the Storage daemon.
38 * Note, we normally carry on a one-way
39 * conversation from this point on with the SD, simply blasting
40 * data to him. To properly know what is going on, we
41 * also run a "heartbeat" monitor which reads the socket and
42 * reacts accordingly (at the moment it has nothing to do
43 * except echo the heartbeat to the Director).
46 bool blast_data_to_storage_daemon(JCR *jcr, char *addr)
50 // TODO landonf: Allow user to specify encryption algorithm
51 crypto_cipher_t cipher = CRYPTO_CIPHER_AES_128_CBC;
53 sd = jcr->store_bsock;
55 set_jcr_job_status(jcr, JS_Running);
57 Dmsg1(300, "bfiled: opened data connection %d to stored\n", sd->fd);
60 CLIENT *client = (CLIENT *)GetNextRes(R_CLIENT, NULL);
64 buf_size = client->max_network_buffer_size;
66 buf_size = 0; /* use default */
68 if (!bnet_set_buffer_size(sd, buf_size, BNET_SETBUF_WRITE)) {
69 set_jcr_job_status(jcr, JS_ErrorTerminated);
70 Jmsg(jcr, M_FATAL, 0, _("Cannot set buffer size FD->SD.\n"));
74 jcr->buf_size = sd->msglen;
75 /* Adjust for compression so that output buffer is
76 * 12 bytes + 0.1% larger than input buffer plus 18 bytes.
77 * This gives a bit extra plus room for the sparse addr if any.
78 * Note, we adjust the read size to be smaller so that the
79 * same output buffer can be used without growing it.
81 jcr->compress_buf_size = jcr->buf_size + ((jcr->buf_size+999) / 1000) + 30;
82 jcr->compress_buf = get_memory(jcr->compress_buf_size);
84 /* Create encryption session data and a cached, DER-encoded session data
85 * structure. We use a single session key for each backup, so we'll encode
86 * the session data only once. */
87 if (jcr->pki_encrypt) {
90 /* Create per-job session encryption context */
91 jcr->pki_session = crypto_session_new(cipher, jcr->pki_readers);
93 /* Get the session data size */
94 if (crypto_session_encode(jcr->pki_session, NULL, &size) == false) {
95 Jmsg(jcr, M_FATAL, 0, _("An error occured while encrypting the stream.\n"));
100 jcr->pki_session_encoded = malloc(size);
101 if (!jcr->pki_session_encoded) {
105 /* Encode session data */
106 if (crypto_session_encode(jcr->pki_session, jcr->pki_session_encoded, &size) == false) {
107 Jmsg(jcr, M_FATAL, 0, _("An error occured while encrypting the stream.\n"));
111 /* ... and store the encoded size */
112 jcr->pki_session_encoded_size = size;
115 Dmsg1(300, "set_find_options ff=%p\n", jcr->ff);
116 set_find_options((FF_PKT *)jcr->ff, jcr->incremental, jcr->mtime);
117 Dmsg0(300, "start find files\n");
119 start_heartbeat_monitor(jcr);
121 jcr->acl_text = get_pool_memory(PM_MESSAGE);
123 /* Subroutine save_file() is called for each file */
124 if (!find_files(jcr, (FF_PKT *)jcr->ff, save_file, (void *)jcr)) {
125 ok = false; /* error */
126 set_jcr_job_status(jcr, JS_ErrorTerminated);
127 // Jmsg(jcr, M_FATAL, 0, _("Find files error.\n"));
130 free_pool_memory(jcr->acl_text);
132 stop_heartbeat_monitor(jcr);
134 bnet_sig(sd, BNET_EOD); /* end of sending data */
140 if (jcr->compress_buf) {
141 free_pool_memory(jcr->compress_buf);
142 jcr->compress_buf = NULL;
145 if (jcr->pki_session) {
146 crypto_session_free(jcr->pki_session);
148 if (jcr->pki_session_encoded) {
149 free(jcr->pki_session_encoded);
152 Dmsg1(100, "end blast_data ok=%d\n", ok);
157 * Called here by find() for each file included.
158 * This is a callback. The original is find_files() above.
160 * Send the file and its data to the Storage daemon.
164 * -1 to ignore file/directory (not used here)
166 static int save_file(FF_PKT *ff_pkt, void *vjcr, bool top_level)
168 int stat, data_stream;
169 DIGEST *digest = NULL;
170 DIGEST *signing_digest = NULL;
171 int digest_stream = STREAM_NONE;
172 // TODO landonf: Allow the user to specify the digest algorithm
174 crypto_digest_t signing_algorithm = CRYPTO_DIGEST_SHA256;
176 crypto_digest_t signing_algorithm = CRYPTO_DIGEST_SHA1;
179 JCR *jcr = (JCR *)vjcr;
181 if (job_canceled(jcr)) {
185 sd = jcr->store_bsock;
186 jcr->num_files_examined++; /* bump total file count */
188 switch (ff_pkt->type) {
189 case FT_LNKSAVED: /* Hard linked, file already saved */
190 Dmsg2(130, "FT_LNKSAVED hard link: %s => %s\n", ff_pkt->fname, ff_pkt->link);
193 Dmsg1(130, "FT_REGE saving: %s\n", ff_pkt->fname);
196 Dmsg1(130, "FT_REG saving: %s\n", ff_pkt->fname);
199 Dmsg2(130, "FT_LNK saving: %s -> %s\n", ff_pkt->fname, ff_pkt->link);
202 return 1; /* not used */
204 Jmsg(jcr, M_INFO, 1, _(" Recursion turned off. Will not descend into %s\n"),
206 ff_pkt->type = FT_DIREND; /* Backup only the directory entry */
209 /* Suppress message for /dev filesystems */
210 if (strncmp(ff_pkt->fname, "/dev/", 5) != 0) {
211 Jmsg(jcr, M_INFO, 1, _(" Filesystem change prohibited. Will not descend into %s\n"),
214 ff_pkt->type = FT_DIREND; /* Backup only the directory entry */
217 Jmsg(jcr, M_INFO, 1, _(" Disallowed filesystem. Will not descend into %s\n"),
219 ff_pkt->type = FT_DIREND; /* Backup only the directory entry */
222 Dmsg1(130, "FT_DIREND: %s\n", ff_pkt->link);
225 Dmsg1(130, "FT_SPEC saving: %s\n", ff_pkt->fname);
228 Dmsg1(130, "FT_RAW saving: %s\n", ff_pkt->fname);
231 Dmsg1(130, "FT_FIFO saving: %s\n", ff_pkt->fname);
235 Jmsg(jcr, M_NOTSAVED, 0, _(" Could not access %s: ERR=%s\n"), ff_pkt->fname,
236 be.strerror(ff_pkt->ff_errno));
242 Jmsg(jcr, M_NOTSAVED, 0, _(" Could not follow link %s: ERR=%s\n"), ff_pkt->fname,
243 be.strerror(ff_pkt->ff_errno));
249 Jmsg(jcr, M_NOTSAVED, 0, _(" Could not stat %s: ERR=%s\n"), ff_pkt->fname,
250 be.strerror(ff_pkt->ff_errno));
256 Jmsg(jcr, M_SKIPPED, 1, _(" Unchanged file skipped: %s\n"), ff_pkt->fname);
259 Jmsg(jcr, M_NOTSAVED, 0, _(" Archive file not saved: %s\n"), ff_pkt->fname);
263 Jmsg(jcr, M_NOTSAVED, 0, _(" Could not open directory %s: ERR=%s\n"), ff_pkt->fname,
264 be.strerror(ff_pkt->ff_errno));
269 Jmsg(jcr, M_NOTSAVED, 0, _(" Unknown file type %d; not saved: %s\n"), ff_pkt->type, ff_pkt->fname);
274 Dmsg1(130, "bfiled: sending %s to stored\n", ff_pkt->fname);
277 * Setup for digest handling. If this fails, the digest will be set to NULL
280 if (ff_pkt->flags & FO_MD5) {
281 digest = crypto_digest_new(CRYPTO_DIGEST_MD5);
282 digest_stream = STREAM_MD5_DIGEST;
284 } else if (ff_pkt->flags & FO_SHA1) {
285 digest = crypto_digest_new(CRYPTO_DIGEST_SHA1);
286 digest_stream = STREAM_SHA1_DIGEST;
288 } else if (ff_pkt->flags & FO_SHA256) {
289 digest = crypto_digest_new(CRYPTO_DIGEST_SHA256);
290 digest_stream = STREAM_SHA256_DIGEST;
292 } else if (ff_pkt->flags & FO_SHA512) {
293 digest = crypto_digest_new(CRYPTO_DIGEST_SHA512);
294 digest_stream = STREAM_SHA512_DIGEST;
297 /* Did digest initialization fail? */
298 if (digest_stream != STREAM_NONE && digest == NULL) {
299 Jmsg(jcr, M_WARNING, 0, _("%s digest initialization failed\n"),
300 stream_to_ascii(digest_stream));
304 * Set up signature digest handling. If this fails, the signature digest will be set to
307 // TODO landonf: We should really only calculate the digest once, for both verification and signing.
309 signing_digest = crypto_digest_new(signing_algorithm);
312 /* Full-stop if a failure occured initializing the signature digest */
313 if (jcr->pki_sign && signing_digest == NULL) {
314 Jmsg(jcr, M_NOTSAVED, 0, _("%s signature digest initialization failed\n"),
315 stream_to_ascii(signing_algorithm));
320 /* Initialise the file descriptor we use for data and other streams. */
322 if (ff_pkt->flags & FO_PORTABLE) {
323 set_portable_backup(&ff_pkt->bfd); /* disable Win32 BackupRead() */
325 if (ff_pkt->reader) {
326 if (!set_prog(&ff_pkt->bfd, ff_pkt->reader, jcr)) {
327 Jmsg(jcr, M_FATAL, 0, _("Python reader program \"%s\" not found.\n"),
333 /* Send attributes -- must be done after binit() */
334 if (!encode_and_send_attributes(jcr, ff_pkt, data_stream)) {
339 * Open any file with data that we intend to save, then save it.
341 * Note, if is_win32_backup, we must open the Directory so that
342 * the BackupRead will save its permissions and ownership streams.
344 if (ff_pkt->type != FT_LNKSAVED && (S_ISREG(ff_pkt->statp.st_mode) &&
345 ff_pkt->statp.st_size > 0) ||
346 ff_pkt->type == FT_RAW || ff_pkt->type == FT_FIFO ||
347 (!is_portable_backup(&ff_pkt->bfd) && ff_pkt->type == FT_DIREND)) {
349 if (ff_pkt->type == FT_FIFO) {
350 tid = start_thread_timer(pthread_self(), 60);
354 if (bopen(&ff_pkt->bfd, ff_pkt->fname, O_RDONLY | O_BINARY, 0) < 0) {
355 ff_pkt->ff_errno = errno;
357 Jmsg(jcr, M_NOTSAVED, 0, _(" Cannot open %s: ERR=%s.\n"), ff_pkt->fname,
361 stop_thread_timer(tid);
367 stop_thread_timer(tid);
371 /* Set up the encryption context, send the session data to the SD */
372 if (jcr->pki_encrypt) {
373 /* Send our header */
374 bnet_fsend(sd, "%ld %d 0", jcr->JobFiles, STREAM_ENCRYPTED_SESSION_DATA);
376 /* Grow the bsock buffer to fit our message if necessary */
377 if ((size_t) sizeof_pool_memory(sd->msg) < jcr->pki_session_encoded_size) {
378 sd->msg = realloc_pool_memory(sd->msg, jcr->pki_session_encoded_size);
381 /* Copy our message over and send it */
382 memcpy(sd->msg, jcr->pki_session_encoded, jcr->pki_session_encoded_size);
383 sd->msglen = jcr->pki_session_encoded_size;
384 jcr->JobBytes += sd->msglen;
387 bnet_sig(sd, BNET_EOD);
390 stat = send_data(jcr, data_stream, ff_pkt, digest, signing_digest);
391 bclose(&ff_pkt->bfd);
397 #ifdef HAVE_DARWIN_OS
398 /* Regular files can have resource forks and Finder Info */
399 if (ff_pkt->type != FT_LNKSAVED && (S_ISREG(ff_pkt->statp.st_mode) &&
400 ff_pkt->flags & FO_HFSPLUS)) {
401 if (ff_pkt->hfsinfo.rsrclength > 0) {
403 if (!bopen_rsrc(&ff_pkt->bfd, ff_pkt->fname, O_RDONLY | O_BINARY, 0) < 0) {
404 ff_pkt->ff_errno = errno;
406 Jmsg(jcr, M_NOTSAVED, -1, _(" Cannot open resource fork for %s: ERR=%s.\n"), ff_pkt->fname,
409 if (is_bopen(&ff_pkt->bfd)) {
410 bclose(&ff_pkt->bfd);
414 flags = ff_pkt->flags;
415 ff_pkt->flags &= ~(FO_GZIP|FO_SPARSE);
416 stat = send_data(jcr, STREAM_MACOS_FORK_DATA, ff_pkt, digest, signing_digest);
417 ff_pkt->flags = flags;
418 bclose(&ff_pkt->bfd);
424 Dmsg1(300, "Saving Finder Info for \"%s\"\n", ff_pkt->fname);
425 bnet_fsend(sd, "%ld %d 0", jcr->JobFiles, STREAM_HFSPLUS_ATTRIBUTES);
426 Dmsg1(300, "bfiled>stored:header %s\n", sd->msg);
427 memcpy(sd->msg, ff_pkt->hfsinfo.fndrinfo, 32);
430 crypto_digest_update(digest, sd->msg, sd->msglen);
432 if (signing_digest) {
433 crypto_digest_update(signing_digest, sd->msg, sd->msglen);
436 bnet_sig(sd, BNET_EOD);
440 if (ff_pkt->flags & FO_ACL) {
441 /* Read access ACLs for files, dirs and links */
442 if (!read_and_send_acl(jcr, BACL_TYPE_ACCESS, STREAM_UNIX_ATTRIBUTES_ACCESS_ACL)) {
445 /* Directories can have default ACLs too */
446 if (ff_pkt->type == FT_DIREND && (BACL_CAP & BACL_CAP_DEFAULTS_DIR)) {
447 if (!read_and_send_acl(jcr, BACL_TYPE_DEFAULT, STREAM_UNIX_ATTRIBUTES_DEFAULT_ACL)) {
453 /* Terminate the signing digest and send it to the Storage daemon */
454 if (signing_digest) {
459 if ((sig = crypto_sign_new()) == NULL) {
460 Jmsg(jcr, M_FATAL, 0, _("Failed to allocate memory for stream signature.\n"));
464 if (crypto_sign_add_signer(sig, signing_digest, jcr->pki_keypair) == false) {
465 Jmsg(jcr, M_FATAL, 0, _("An error occured while signing the stream.\n"));
469 /* Get signature size */
470 if (crypto_sign_encode(sig, NULL, &size) == false) {
471 Jmsg(jcr, M_FATAL, 0, _("An error occured while signing the stream.\n"));
475 /* Allocate signature data buffer */
478 crypto_sign_free(sig);
482 /* Encode signature data */
483 if (crypto_sign_encode(sig, buf, &size) == false) {
484 Jmsg(jcr, M_FATAL, 0, _("An error occured while signing the stream.\n"));
488 /* Send our header */
489 bnet_fsend(sd, "%ld %d 0", jcr->JobFiles, STREAM_SIGNED_DIGEST);
490 Dmsg1(300, "bfiled>stored:header %s\n", sd->msg);
492 /* Grow the bsock buffer to fit our message if necessary */
493 if ((size_t) sizeof_pool_memory(sd->msg) < size) {
494 sd->msg = realloc_pool_memory(sd->msg, size);
497 /* Copy our message over and send it */
498 memcpy(sd->msg, buf, size);
501 bnet_sig(sd, BNET_EOD); /* end of checksum */
503 crypto_digest_free(signing_digest);
504 crypto_sign_free(sig);
508 /* Terminate any digest and send it to Storage daemon and the Director */
510 char md[CRYPTO_DIGEST_MAX_SIZE];
515 if (crypto_digest_finalize(digest, &md, &size)) {
516 bnet_fsend(sd, "%ld %d 0", jcr->JobFiles, digest_stream);
517 Dmsg1(300, "bfiled>stored:header %s\n", sd->msg);
518 memcpy(sd->msg, md, size);
521 bnet_sig(sd, BNET_EOD); /* end of checksum */
524 crypto_digest_free(digest);
531 * Send data read from an already open file descriptor.
533 * We return 1 on sucess and 0 on errors.
536 * We use ff_pkt->statp.st_size when FO_SPARSE.
537 * Currently this is not a problem as the only other stream, resource forks,
538 * are not handled as sparse files.
540 int send_data(JCR *jcr, int stream, FF_PKT *ff_pkt, DIGEST *digest, DIGEST *signing_digest)
542 BSOCK *sd = jcr->store_bsock;
543 uint64_t fileAddr = 0; /* file address */
545 int rsize = jcr->buf_size; /* read buffer size */
547 #ifdef FD_NO_SEND_TEST
552 rbuf = sd->msg; /* read buffer */
553 wbuf = sd->msg; /* write buffer */
556 Dmsg1(300, "Saving data, type=%d\n", ff_pkt->type);
560 uLong compress_len, max_compress_len = 0;
561 const Bytef *cbuf = NULL;
563 if (ff_pkt->flags & FO_GZIP) {
564 if (ff_pkt->flags & FO_SPARSE) {
565 cbuf = (Bytef *)jcr->compress_buf + SPARSE_FADDR_SIZE;
566 max_compress_len = jcr->compress_buf_size - SPARSE_FADDR_SIZE;
568 cbuf = (Bytef *)jcr->compress_buf;
569 max_compress_len = jcr->compress_buf_size; /* set max length */
571 wbuf = jcr->compress_buf; /* compressed output here */
576 * Send Data header to Storage daemon
577 * <file-index> <stream> <info>
579 if (!bnet_fsend(sd, "%ld %d 0", jcr->JobFiles, stream)) {
580 Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
584 Dmsg1(300, ">stored: datahdr %s\n", sd->msg);
587 * Make space at beginning of buffer for fileAddr because this
588 * same buffer will be used for writing if compression if off.
590 if (ff_pkt->flags & FO_SPARSE) {
591 rbuf += SPARSE_FADDR_SIZE;
592 rsize -= SPARSE_FADDR_SIZE;
593 #ifdef HAVE_FREEBSD_OS
595 * To read FreeBSD partitions, the read size must be
598 rsize = (rsize/512) * 512;
602 /* a RAW device read on win32 only works if the buffer is a multiple of 512 */
604 if (S_ISBLK(ff_pkt->statp.st_mode))
605 rsize = (rsize/512) * 512;
611 while ((sd->msglen=(uint32_t)bread(&ff_pkt->bfd, rbuf, rsize)) > 0) {
614 /* Check for sparse blocks */
615 if (ff_pkt->flags & FO_SPARSE) {
617 if (sd->msglen == rsize &&
618 fileAddr+sd->msglen < (uint64_t)ff_pkt->statp.st_size ||
619 ((ff_pkt->type == FT_RAW || ff_pkt->type == FT_FIFO) &&
620 (uint64_t)ff_pkt->statp.st_size == 0)) {
621 sparseBlock = is_buf_zero(rbuf, rsize);
624 ser_begin(wbuf, SPARSE_FADDR_SIZE);
625 ser_uint64(fileAddr); /* store fileAddr in begin of buffer */
628 jcr->ReadBytes += sd->msglen; /* count bytes read */
629 fileAddr += sd->msglen;
631 /* Update checksum if requested */
633 crypto_digest_update(digest, rbuf, sd->msglen);
636 /* Update signing digest if requested */
637 if (signing_digest) {
638 crypto_digest_update(signing_digest, rbuf, sd->msglen);
642 /* Do compression if turned on */
643 if (!sparseBlock && ff_pkt->flags & FO_GZIP) {
645 compress_len = max_compress_len;
646 Dmsg4(400, "cbuf=0x%x len=%u rbuf=0x%x len=%u\n", cbuf, compress_len,
648 /* NOTE! This call modifies compress_len !!! */
649 if ((zstat=compress2((Bytef *)cbuf, &compress_len,
650 (const Bytef *)rbuf, (uLong)sd->msglen,
651 ff_pkt->GZIP_level)) != Z_OK) {
652 Jmsg(jcr, M_FATAL, 0, _("Compression error: %d\n"), zstat);
655 set_jcr_job_status(jcr, JS_ErrorTerminated);
658 Dmsg2(400, "compressed len=%d uncompressed len=%d\n",
659 compress_len, sd->msglen);
661 sd->msglen = compress_len; /* set compressed length */
665 /* Send the buffer to the Storage daemon */
667 if (ff_pkt->flags & FO_SPARSE) {
668 sd->msglen += SPARSE_FADDR_SIZE; /* include fileAddr in size */
670 sd->msg = wbuf; /* set correct write buffer */
671 if (!bnet_send(sd)) {
672 Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
674 sd->msg = msgsave; /* restore bnet buffer */
679 Dmsg1(130, "Send data to SD len=%d\n", sd->msglen);
681 jcr->JobBytes += sd->msglen; /* count bytes saved possibly compressed */
682 sd->msg = msgsave; /* restore read buffer */
684 } /* end while read file data */
687 if (sd->msglen < 0) {
689 Jmsg(jcr, M_ERROR, 0, _("Read error on file %s. ERR=%s\n"),
690 ff_pkt->fname, be.strerror(ff_pkt->bfd.berrno));
691 if (jcr->Errors++ > 1000) { /* insanity check */
692 Jmsg(jcr, M_FATAL, 0, _("Too many errors.\n"));
697 if (!bnet_sig(sd, BNET_EOD)) { /* indicate end of file data */
698 Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
707 * Read and send an ACL for the last encountered file.
709 static bool read_and_send_acl(JCR *jcr, int acltype, int stream)
712 BSOCK *sd = jcr->store_bsock;
715 #ifdef FD_NO_SEND_TEST
719 len = bacl_get(jcr, acltype);
721 Jmsg1(jcr, M_WARNING, 0, _("Error reading ACL of %s\n"), jcr->last_fname);
725 return true; /* no ACL */
729 if (!bnet_fsend(sd, "%ld %d 0", jcr->JobFiles, stream)) {
730 Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
735 /* Send the buffer to the storage deamon */
736 Dmsg2(400, "Backing up ACL type 0x%2x <%s>\n", acltype, jcr->acl_text);
738 sd->msg = jcr->acl_text;
739 sd->msglen = len + 1;
740 if (!bnet_send(sd)) {
743 Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
748 jcr->JobBytes += sd->msglen;
750 if (!bnet_sig(sd, BNET_EOD)) {
751 Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
756 Dmsg1(200, "ACL of file: %s successfully backed up!\n", jcr->last_fname);
761 static bool encode_and_send_attributes(JCR *jcr, FF_PKT *ff_pkt, int &data_stream)
763 BSOCK *sd = jcr->store_bsock;
764 char attribs[MAXSTRING];
765 char attribsEx[MAXSTRING];
768 #ifdef FD_NO_SEND_TEST
772 /* Find what data stream we will use, then encode the attributes */
773 data_stream = select_data_stream(ff_pkt);
774 encode_stat(attribs, ff_pkt, data_stream);
776 /* Now possibly extend the attributes */
777 attr_stream = encode_attribsEx(jcr, attribsEx, ff_pkt);
779 Dmsg3(300, "File %s\nattribs=%s\nattribsEx=%s\n", ff_pkt->fname, attribs, attribsEx);
782 jcr->JobFiles++; /* increment number of files sent */
783 ff_pkt->FileIndex = jcr->JobFiles; /* return FileIndex */
784 pm_strcpy(jcr->last_fname, ff_pkt->fname);
788 * Send Attributes header to Storage daemon
789 * <file-index> <stream> <info>
791 if (!bnet_fsend(sd, "%ld %d 0", jcr->JobFiles, attr_stream)) {
792 Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
796 Dmsg1(300, ">stored: attrhdr %s\n", sd->msg);
799 * Send file attributes to Storage daemon
802 * Filename (full path)
804 * Link name (if type==FT_LNK or FT_LNKSAVED)
805 * Encoded extended-attributes (for Win32)
807 * For a directory, link is the same as fname, but with trailing
808 * slash. For a linked file, link is the link.
810 if (ff_pkt->type == FT_LNK || ff_pkt->type == FT_LNKSAVED) {
811 Dmsg2(300, "Link %s to %s\n", ff_pkt->fname, ff_pkt->link);
812 stat = bnet_fsend(sd, "%ld %d %s%c%s%c%s%c%s%c", jcr->JobFiles,
813 ff_pkt->type, ff_pkt->fname, 0, attribs, 0, ff_pkt->link, 0,
815 } else if (ff_pkt->type == FT_DIREND) {
816 /* Here link is the canonical filename (i.e. with trailing slash) */
817 stat = bnet_fsend(sd, "%ld %d %s%c%s%c%c%s%c", jcr->JobFiles,
818 ff_pkt->type, ff_pkt->link, 0, attribs, 0, 0, attribsEx, 0);
820 stat = bnet_fsend(sd, "%ld %d %s%c%s%c%c%s%c", jcr->JobFiles,
821 ff_pkt->type, ff_pkt->fname, 0, attribs, 0, 0, attribsEx, 0);
824 Dmsg2(300, ">stored: attr len=%d: %s\n", sd->msglen, sd->msg);
826 Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
830 bnet_sig(sd, BNET_EOD); /* indicate end of attributes data */