X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=bacula%2Fsrc%2Ffiled%2Fbackup.c;h=0431a0fc0a0bab1598e82e5d305a4976cf02510e;hb=9cdeafde391bd0c57693398f3b9eac9404892f1b;hp=23a2a79c12363584f98e72189866f93cc4219496;hpb=7d161afa7dfc279425499a2510ced530015b5c03;p=bacula%2Fbacula diff --git a/bacula/src/filed/backup.c b/bacula/src/filed/backup.c index 23a2a79c12..0431a0fc0a 100644 --- a/bacula/src/filed/backup.c +++ b/bacula/src/filed/backup.c @@ -1,5 +1,5 @@ /* - * Bacula File Daemon backup.c send file attributes and data + * Bacula File Daemon backup.c send file attributes and data * to the Storage daemon. * * Kern Sibbald, March MM @@ -8,35 +8,28 @@ * */ /* - Copyright (C) 2000-2004 Kern Sibbald + Copyright (C) 2000-2005 Kern Sibbald This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License as - published by the Free Software Foundation; either version 2 of - the License, or (at your option) any later version. + modify it under the terms of the GNU General Public License + version 2 as amended with additional clauses defined in the + file LICENSE in the main source directory. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public - License along with this program; if not, write to the Free - Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, - MA 02111-1307, USA. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + the file LICENSE for additional details. */ #include "bacula.h" #include "filed.h" -#ifdef HAVE_ACL -#include -#include -#endif - -static int save_file(FF_PKT *ff_pkt, void *pkt); -static int send_data(int stream, FF_PKT *ff_pkt, BSOCK *sd, JCR *jcr, struct CHKSUM *chksum); +/* Forward referenced functions */ +static int save_file(FF_PKT *ff_pkt, void *pkt, bool top_level); +static int send_data(JCR *jcr, int stream, FF_PKT *ff_pkt, DIGEST *digest, DIGEST *signature_digest); +static bool encode_and_send_attributes(JCR *jcr, FF_PKT *ff_pkt, int &data_stream); +static bool read_and_send_acl(JCR *jcr, int acltype, int stream); /* * Find all the requested files and send them @@ -68,7 +61,7 @@ bool blast_data_to_storage_daemon(JCR *jcr, char *addr) if (client) { buf_size = client->max_network_buffer_size; } else { - buf_size = 0; /* use default */ + buf_size = 0; /* use default */ } if (!bnet_set_buffer_size(sd, buf_size, BNET_SETBUF_WRITE)) { set_jcr_job_status(jcr, JS_ErrorTerminated); @@ -92,16 +85,20 @@ bool blast_data_to_storage_daemon(JCR *jcr, char *addr) start_heartbeat_monitor(jcr); + jcr->acl_text = get_pool_memory(PM_MESSAGE); + /* Subroutine save_file() is called for each file */ if (!find_files(jcr, (FF_PKT *)jcr->ff, save_file, (void *)jcr)) { - ok = false; /* error */ + ok = false; /* error */ set_jcr_job_status(jcr, JS_ErrorTerminated); // Jmsg(jcr, M_FATAL, 0, _("Find files error.\n")); } + free_pool_memory(jcr->acl_text); + stop_heartbeat_monitor(jcr); - bnet_sig(sd, BNET_EOD); /* end data connection */ + bnet_sig(sd, BNET_EOD); /* end of sending data */ if (jcr->big_buf) { free(jcr->big_buf); @@ -111,27 +108,32 @@ bool blast_data_to_storage_daemon(JCR *jcr, char *addr) free_pool_memory(jcr->compress_buf); jcr->compress_buf = NULL; } - Dmsg1(300, "end blast_data stat=%d\n", ok); + Dmsg1(100, "end blast_data ok=%d\n", ok); return ok; } /* * Called here by find() for each file included. - * - * *****FIXME***** add FSMs File System Modules + * This is a callback. The original is find_files() above. * * Send the file and its data to the Storage daemon. * * Returns: 1 if OK - * 0 if error - * -1 to ignore file/directory (not used here) + * 0 if error + * -1 to ignore file/directory (not used here) */ -static int save_file(FF_PKT *ff_pkt, void *vjcr) +static int save_file(FF_PKT *ff_pkt, void *vjcr, bool top_level) { - char attribs[MAXSTRING]; - char attribsEx[MAXSTRING]; - int stat, attr_stream, data_stream; - struct CHKSUM chksum; + int stat, data_stream; + DIGEST *digest = NULL; + DIGEST *signing_digest = NULL; + int digest_stream = STREAM_NONE; + // TODO landonf: Allow the user to specify the digest algorithm +#ifdef HAVE_SHA2 + crypto_digest_t signing_algorithm = CRYPTO_DIGEST_SHA256; +#else + crypto_digest_t signing_algorithm = CRYPTO_DIGEST_SHA1; +#endif BSOCK *sd; JCR *jcr = (JCR *)vjcr; @@ -140,10 +142,10 @@ static int save_file(FF_PKT *ff_pkt, void *vjcr) } sd = jcr->store_bsock; - jcr->num_files_examined++; /* bump total file count */ + jcr->num_files_examined++; /* bump total file count */ switch (ff_pkt->type) { - case FT_LNKSAVED: /* Hard linked, file already saved */ + case FT_LNKSAVED: /* Hard linked, file already saved */ Dmsg2(130, "FT_LNKSAVED hard link: %s => %s\n", ff_pkt->fname, ff_pkt->link); break; case FT_REGE: @@ -156,23 +158,27 @@ static int save_file(FF_PKT *ff_pkt, void *vjcr) Dmsg2(130, "FT_LNK saving: %s -> %s\n", ff_pkt->fname, ff_pkt->link); break; case FT_DIRBEGIN: - return 1; /* not used */ + return 1; /* not used */ case FT_NORECURSE: + Jmsg(jcr, M_INFO, 1, _(" Recursion turned off. Will not descend into %s\n"), + ff_pkt->fname); + ff_pkt->type = FT_DIREND; /* Backup only the directory entry */ + break; case FT_NOFSCHG: + /* Suppress message for /dev filesystems */ + if (strncmp(ff_pkt->fname, "/dev/", 5) != 0) { + Jmsg(jcr, M_INFO, 1, _(" Filesystem change prohibited. Will not descend into %s\n"), + ff_pkt->fname); + } + ff_pkt->type = FT_DIREND; /* Backup only the directory entry */ + break; case FT_INVALIDFS: + Jmsg(jcr, M_INFO, 1, _(" Disallowed filesystem. Will not descend into %s\n"), + ff_pkt->fname); + ff_pkt->type = FT_DIREND; /* Backup only the directory entry */ + break; case FT_DIREND: - if (ff_pkt->type == FT_NORECURSE) { - Jmsg(jcr, M_INFO, 1, _(" Recursion turned off. Will not descend into %s\n"), - ff_pkt->fname); - } else if (ff_pkt->type == FT_NOFSCHG) { - Jmsg(jcr, M_INFO, 1, _(" File system change prohibited. Will not descend into %s\n"), - ff_pkt->fname); - } else if (ff_pkt->type == FT_INVALIDFS) { - Jmsg(jcr, M_INFO, 1, _(" Disallowed filesystem. Will not descend into %s\n"), - ff_pkt->fname); - } - ff_pkt->type = FT_DIREND; /* value is used below */ - Dmsg1(130, "FT_DIR saving: %s\n", ff_pkt->link); + Dmsg1(130, "FT_DIREND: %s\n", ff_pkt->link); break; case FT_SPEC: Dmsg1(130, "FT_SPEC saving: %s\n", ff_pkt->fname); @@ -185,25 +191,22 @@ static int save_file(FF_PKT *ff_pkt, void *vjcr) break; case FT_NOACCESS: { berrno be; - be.set_errno(ff_pkt->ff_errno); Jmsg(jcr, M_NOTSAVED, 0, _(" Could not access %s: ERR=%s\n"), ff_pkt->fname, - be.strerror()); + be.strerror(ff_pkt->ff_errno)); jcr->Errors++; return 1; } case FT_NOFOLLOW: { berrno be; - be.set_errno(ff_pkt->ff_errno); Jmsg(jcr, M_NOTSAVED, 0, _(" Could not follow link %s: ERR=%s\n"), ff_pkt->fname, - be.strerror()); + be.strerror(ff_pkt->ff_errno)); jcr->Errors++; return 1; } case FT_NOSTAT: { berrno be; - be.set_errno(ff_pkt->ff_errno); Jmsg(jcr, M_NOTSAVED, 0, _(" Could not stat %s: ERR=%s\n"), ff_pkt->fname, - be.strerror()); + be.strerror(ff_pkt->ff_errno)); jcr->Errors++; return 1; } @@ -216,9 +219,8 @@ static int save_file(FF_PKT *ff_pkt, void *vjcr) return 1; case FT_NOOPEN: { berrno be; - be.set_errno(ff_pkt->ff_errno); Jmsg(jcr, M_NOTSAVED, 0, _(" Could not open directory %s: ERR=%s\n"), ff_pkt->fname, - be.strerror()); + be.strerror(ff_pkt->ff_errno)); jcr->Errors++; return 1; } @@ -230,80 +232,66 @@ static int save_file(FF_PKT *ff_pkt, void *vjcr) Dmsg1(130, "bfiled: sending %s to stored\n", ff_pkt->fname); - /* Find what data stream we will use, then encode the attributes */ - data_stream = select_data_stream(ff_pkt); - encode_stat(attribs, ff_pkt, data_stream); + /* + * Setup for digest handling. If this fails, the digest will be set to NULL + * and not used. + */ + if (ff_pkt->flags & FO_MD5) { + digest = crypto_digest_new(CRYPTO_DIGEST_MD5); + digest_stream = STREAM_MD5_DIGEST; - /* Now possibly extend the attributes */ - attr_stream = encode_attribsEx(jcr, attribsEx, ff_pkt); + } else if (ff_pkt->flags & FO_SHA1) { + digest = crypto_digest_new(CRYPTO_DIGEST_SHA1); + digest_stream = STREAM_SHA1_DIGEST; - Dmsg3(300, "File %s\nattribs=%s\nattribsEx=%s\n", ff_pkt->fname, attribs, attribsEx); + } else if (ff_pkt->flags & FO_SHA256) { + digest = crypto_digest_new(CRYPTO_DIGEST_SHA256); + digest_stream = STREAM_SHA256_DIGEST; - P(jcr->mutex); - jcr->JobFiles++; /* increment number of files sent */ - ff_pkt->FileIndex = jcr->JobFiles; /* return FileIndex */ - pm_strcpy(jcr->last_fname, ff_pkt->fname); - V(jcr->mutex); + } else if (ff_pkt->flags & FO_SHA512) { + digest = crypto_digest_new(CRYPTO_DIGEST_SHA512); + digest_stream = STREAM_SHA512_DIGEST; + } - /* - * Send Attributes header to Storage daemon - * - */ - if (!bnet_fsend(sd, "%ld %d 0", jcr->JobFiles, attr_stream)) { - berrno be; - Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"), - bnet_strerror(sd)); - return 0; + /* Did digest initialization fail? */ + if (digest_stream != STREAM_NONE && digest == NULL) { + Jmsg(jcr, M_WARNING, 0, _("%s digest initialization failed\n"), + stream_to_ascii(digest_stream)); } - Dmsg1(300, ">stored: attrhdr %s\n", sd->msg); /* - * Send file attributes to Storage daemon - * File_index - * File type - * Filename (full path) - * Encoded attributes - * Link name (if type==FT_LNK or FT_LNKSAVED) - * Encoded extended-attributes (for Win32) - * - * For a directory, link is the same as fname, but with trailing - * slash. For a linked file, link is the link. + * Set up signature digest handling. If this fails, the signature digest will be set to + * NULL and not used. */ - if (ff_pkt->type == FT_LNK || ff_pkt->type == FT_LNKSAVED) { - Dmsg2(300, "Link %s to %s\n", ff_pkt->fname, ff_pkt->link); - stat = bnet_fsend(sd, "%ld %d %s%c%s%c%s%c%s%c", jcr->JobFiles, - ff_pkt->type, ff_pkt->fname, 0, attribs, 0, ff_pkt->link, 0, - attribsEx, 0); - } else if (ff_pkt->type == FT_DIREND) { - /* Here link is the canonical filename (i.e. with trailing slash) */ - stat = bnet_fsend(sd, "%ld %d %s%c%s%c%c%s%c", jcr->JobFiles, - ff_pkt->type, ff_pkt->link, 0, attribs, 0, 0, attribsEx, 0); - } else { - stat = bnet_fsend(sd, "%ld %d %s%c%s%c%c%s%c", jcr->JobFiles, - ff_pkt->type, ff_pkt->fname, 0, attribs, 0, 0, attribsEx, 0); + // TODO landonf: We should really only calculate the digest once, for both verification and signing. + if (jcr->pki_sign) { + signing_digest = crypto_digest_new(signing_algorithm); } - Dmsg2(300, ">stored: attr len=%d: %s\n", sd->msglen, sd->msg); - if (!stat) { - berrno be; - Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"), - bnet_strerror(sd)); - return 0; + /* Full-stop if a failure occured initializing the signature digest */ + if (jcr->pki_sign && signing_digest == NULL) { + Jmsg(jcr, M_NOTSAVED, 0, _("%s signature digest initialization failed\n"), + stream_to_ascii(signing_algorithm)); + jcr->Errors++; + return 1; } - bnet_sig(sd, BNET_EOD); /* indicate end of attributes data */ - - /* - * Setup for signature handling. - * Then initialise the file descriptor we use for data and other streams. - */ - chksum_init(&chksum, ff_pkt->flags); + /* Initialise the file descriptor we use for data and other streams. */ binit(&ff_pkt->bfd); if (ff_pkt->flags & FO_PORTABLE) { set_portable_backup(&ff_pkt->bfd); /* disable Win32 BackupRead() */ } if (ff_pkt->reader) { - set_prog(&ff_pkt->bfd, ff_pkt->reader, jcr); + if (!set_prog(&ff_pkt->bfd, ff_pkt->reader, jcr)) { + Jmsg(jcr, M_FATAL, 0, _("Python reader program \"%s\" not found.\n"), + ff_pkt->reader); + return 0; + } + } + + /* Send attributes -- must be done after binit() */ + if (!encode_and_send_attributes(jcr, ff_pkt, data_stream)) { + return 0; } /* @@ -313,63 +301,63 @@ static int save_file(FF_PKT *ff_pkt, void *vjcr) * the BackupRead will save its permissions and ownership streams. */ if (ff_pkt->type != FT_LNKSAVED && (S_ISREG(ff_pkt->statp.st_mode) && - ff_pkt->statp.st_size > 0) || - ff_pkt->type == FT_RAW || ff_pkt->type == FT_FIFO || - (!is_portable_backup(&ff_pkt->bfd) && ff_pkt->type == FT_DIREND)) { + ff_pkt->statp.st_size > 0) || + ff_pkt->type == FT_RAW || ff_pkt->type == FT_FIFO || + (!is_portable_backup(&ff_pkt->bfd) && ff_pkt->type == FT_DIREND)) { btimer_t *tid; if (ff_pkt->type == FT_FIFO) { - tid = start_thread_timer(pthread_self(), 60); + tid = start_thread_timer(pthread_self(), 60); } else { - tid = NULL; + tid = NULL; } if (bopen(&ff_pkt->bfd, ff_pkt->fname, O_RDONLY | O_BINARY, 0) < 0) { - ff_pkt->ff_errno = errno; - berrno be; + ff_pkt->ff_errno = errno; + berrno be; Jmsg(jcr, M_NOTSAVED, 0, _(" Cannot open %s: ERR=%s.\n"), ff_pkt->fname, - be.strerror()); - jcr->Errors++; - if (tid) { - stop_thread_timer(tid); - tid = NULL; - } - return 1; + be.strerror()); + jcr->Errors++; + if (tid) { + stop_thread_timer(tid); + tid = NULL; + } + return 1; } if (tid) { - stop_thread_timer(tid); - tid = NULL; + stop_thread_timer(tid); + tid = NULL; } - stat = send_data(data_stream, ff_pkt, sd, jcr, &chksum); + stat = send_data(jcr, data_stream, ff_pkt, digest, signing_digest); bclose(&ff_pkt->bfd); if (!stat) { - return 0; + return 0; } } #ifdef HAVE_DARWIN_OS - /* Open resource fork if necessary and save content */ + /* Regular files can have resource forks and Finder Info */ if (ff_pkt->type != FT_LNKSAVED && (S_ISREG(ff_pkt->statp.st_mode) && - ff_pkt->flags & FO_HFSPLUS)) { + ff_pkt->flags & FO_HFSPLUS)) { if (ff_pkt->hfsinfo.rsrclength > 0) { - int flags; - if (!bopen_rsrc(&ff_pkt->bfd, ff_pkt->fname, O_RDONLY | O_BINARY, 0) < 0) { - ff_pkt->ff_errno = errno; - berrno be; + int flags; + if (!bopen_rsrc(&ff_pkt->bfd, ff_pkt->fname, O_RDONLY | O_BINARY, 0) < 0) { + ff_pkt->ff_errno = errno; + berrno be; Jmsg(jcr, M_NOTSAVED, -1, _(" Cannot open resource fork for %s: ERR=%s.\n"), ff_pkt->fname, - be.strerror()); - jcr->Errors++; - if (is_bopen(&ff_pkt->bfd)) { - bclose(&ff_pkt->bfd); - } - return 1; - } - flags = ff_pkt->flags; - ff_pkt->flags &= ~(FO_GZIP|FO_SPARSE); - stat = send_data(STREAM_MACOS_FORK_DATA, ff_pkt, sd, jcr, &chksum); - ff_pkt->flags = flags; - bclose(&ff_pkt->bfd); - if (!stat) { - return 0; - } + be.strerror()); + jcr->Errors++; + if (is_bopen(&ff_pkt->bfd)) { + bclose(&ff_pkt->bfd); + } + return 1; + } + flags = ff_pkt->flags; + ff_pkt->flags &= ~(FO_GZIP|FO_SPARSE); + stat = send_data(jcr, STREAM_MACOS_FORK_DATA, ff_pkt, digest); + ff_pkt->flags = flags; + bclose(&ff_pkt->bfd); + if (!stat) { + return 0; + } } Dmsg1(300, "Saving Finder Info for \"%s\"\n", ff_pkt->fname); @@ -377,143 +365,102 @@ static int save_file(FF_PKT *ff_pkt, void *vjcr) Dmsg1(300, "bfiled>stored:header %s\n", sd->msg); memcpy(sd->msg, ff_pkt->hfsinfo.fndrinfo, 32); sd->msglen = 32; - chksum_update(&chksum, (unsigned char *)sd->msg, sd->msglen); + if (digest) { + crypto_digest_update(digest, sd->msg, sd->msglen); + } + if (signature_digest) { + crypto_digest_update(signature_digest, sd->msg, sd->msglen); + } bnet_send(sd); bnet_sig(sd, BNET_EOD); } #endif -#ifdef HAVE_ACL - /*** FIXME ***/ - /* ACL stream */ if (ff_pkt->flags & FO_ACL) { - char *acl_text = NULL; - char *aclDef_text = NULL; - - /* Read ACLs for files, dirs and links */ - if (ff_pkt->type == FT_DIREND) { - /* Directory: Check for default ACL*/ - acl_t myDefAcl = acl_get_file(ff_pkt->fname, ACL_TYPE_DEFAULT); - /* Check for Access ACL */ - acl_t myAccAcl = acl_get_file(ff_pkt->fname, ACL_TYPE_ACCESS); - if (!myDefAcl || !myAccAcl) { - Jmsg1(jcr, M_WARNING, 0, "Error while trying to get ACL of directory: %s!\n", ff_pkt->fname); - } - if(myDefAcl){ - aclDef_text = acl_to_any_text(myDefAcl, NULL, ',', TEXT_ABBREVIATE); - acl_free(myDefAcl); - } - if(myAccAcl){ - acl_text = acl_to_any_text(myAccAcl, NULL, ',', TEXT_ABBREVIATE); - acl_free(myAccAcl); - } - } else { - /* Files or links */ - acl_t myAcl = acl_get_file(ff_pkt->fname, ACL_TYPE_ACCESS); - if (!myAcl) { - Jmsg1(jcr, M_WARNING, 0, "Error while trying to get ACL of file: %s!\n", ff_pkt->fname); - acl_free(myAcl); - } - acl_text = acl_to_any_text(myAcl, NULL, ',', TEXT_ABBREVIATE); - acl_free(myAcl); + /* Read access ACLs for files, dirs and links */ + if (!read_and_send_acl(jcr, BACL_TYPE_ACCESS, STREAM_UNIX_ATTRIBUTES_ACCESS_ACL)) { + return 0; } + /* Directories can have default ACLs too */ + if (ff_pkt->type == FT_DIREND && (BACL_CAP & BACL_CAP_DEFAULTS_DIR)) { + if (!read_and_send_acl(jcr, BACL_TYPE_DEFAULT, STREAM_UNIX_ATTRIBUTES_DEFAULT_ACL)) { + return 0; + } + } + } - POOLMEM *msgsave; + /* Terminate the signing digest and send it to the Storage daemon */ + if (signing_digest) { + SIGNATURE *sig; + size_t size = 0; + void *buf; - /* If there is an ACL, send it to the Storage daemon */ - if (acl_text != NULL) { - sd = jcr->store_bsock; - pm_strcpy(&jcr->last_fname, ff_pkt->fname); + if ((sig = crypto_sign_new()) == NULL) { + Jmsg(jcr, M_FATAL, 0, _("Failed to allocate memory for stream signature.\n")); + return 0; + } + if (crypto_sign_add_signer(sig, signing_digest, jcr->pki_keypair) == false) { + Jmsg(jcr, M_FATAL, 0, _("An error occured while signing the stream.\n")); + return 0; + } - // Send ACL header - if (!bnet_fsend(sd, "%ld %d 0", jcr->JobFiles, STREAM_UNIX_ATTRIBUTES_ACCESS_ACL)) { - berrno be; - Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"), - bnet_strerror(sd)); - return 0; - } - - /* Send the buffer to the storage deamon */ - msgsave = sd->msg; - sd->msg = acl_text; - sd->msglen = strlen(acl_text) + 1; - if (!bnet_send(sd)) { - berrno be; - sd->msg = msgsave; - sd->msglen = 0; - Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"), - bnet_strerror(sd)); - } else { - jcr->JobBytes += sd->msglen; - sd->msg = msgsave; - if (!bnet_sig(sd, BNET_EOD)) { - berrno be; - Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"), - bnet_strerror(sd)); - } else { - Dmsg1(200, "ACL of file: %s successfully backed up!\n", ff_pkt->fname); - } - } + /* Get signature size */ + if (crypto_sign_encode(sig, NULL, &size) == false) { + Jmsg(jcr, M_FATAL, 0, _("An error occured while signing the stream.\n")); + return 0; } - /* If there is an Default ACL, send it to the Storage daemon */ - if (aclDef_text != NULL) { - sd = jcr->store_bsock; - pm_strcpy(&jcr->last_fname, ff_pkt->fname); + /* Allocate signature data buffer */ + buf = malloc(size); + if (!buf) { + free(buf); + return 0; + } - // Send ACL header - if (!bnet_fsend(sd, "%ld %d 0", jcr->JobFiles, STREAM_UNIX_ATTRIBUTES_DEFAULT_ACL)) { - berrno be; - Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"), - bnet_strerror(sd)); - return 0; - } - - // Send the buffer to the storage deamon - msgsave = sd->msg; - sd->msg = aclDef_text; - sd->msglen = strlen(aclDef_text) + 1; - if (!bnet_send(sd)) { - berrno be; - sd->msg = msgsave; - sd->msglen = 0; - Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"), - bnet_strerror(sd)); - } else { - jcr->JobBytes += sd->msglen; - sd->msg = msgsave; - if (!bnet_sig(sd, BNET_EOD)) { - berrno be; - Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"), - bnet_strerror(sd)); - } else { - Dmsg1(200, "ACL of file: %s successfully backed up!\n", ff_pkt->fname); - } - } + /* Encode signature data */ + if (crypto_sign_encode(sig, buf, &size) == false) { + Jmsg(jcr, M_FATAL, 0, _("An error occured while signing the stream.\n")); + return 0; } - } -#endif - /* Terminate any signature and send it to Storage daemon and the Director */ - if (chksum.updated) { - int stream = 0; - chksum_final(&chksum); - if (chksum.type == CHKSUM_MD5) { - stream = STREAM_MD5_SIGNATURE; - } else if (chksum.type == CHKSUM_SHA1) { - stream = STREAM_SHA1_SIGNATURE; - } else { - Jmsg1(jcr, M_WARNING, 0, _("Unknown signature type %i.\n"), chksum.type); + /* Send our header */ + bnet_fsend(sd, "%ld %d 0", jcr->JobFiles, STREAM_SIGNED_DIGEST); + Dmsg1(300, "bfiled>stored:header %s\n", sd->msg); + + /* Grow the bsock buffer to fit our message if necessary */ + if ((size_t) sizeof_pool_memory(sd->msg) < size) { + sd->msg = realloc_pool_memory(sd->msg, size); } - if (stream != 0) { - bnet_fsend(sd, "%ld %d 0", jcr->JobFiles, stream); + + /* Copy our message over and send it */ + memcpy(sd->msg, buf, size); + sd->msglen = size; + bnet_send(sd); + bnet_sig(sd, BNET_EOD); /* end of checksum */ + + crypto_digest_free(signing_digest); + crypto_sign_free(sig); + free(buf); + } + + /* Terminate any digest and send it to Storage daemon and the Director */ + if (digest) { + char md[CRYPTO_DIGEST_MAX_SIZE]; + size_t size; + + size = sizeof(md); + + if (crypto_digest_finalize(digest, &md, &size)) { + bnet_fsend(sd, "%ld %d 0", jcr->JobFiles, digest_stream); Dmsg1(300, "bfiled>stored:header %s\n", sd->msg); - memcpy(sd->msg, chksum.signature, chksum.length); - sd->msglen = chksum.length; - bnet_send(sd); - bnet_sig(sd, BNET_EOD); /* end of checksum */ + memcpy(sd->msg, md, size); + sd->msglen = size; + bnet_send(sd); + bnet_sig(sd, BNET_EOD); /* end of checksum */ } + + crypto_digest_free(digest); } return 1; @@ -529,16 +476,20 @@ static int save_file(FF_PKT *ff_pkt, void *vjcr) * Currently this is not a problem as the only other stream, resource forks, * are not handled as sparse files. */ -int send_data(int stream, FF_PKT *ff_pkt, BSOCK *sd, JCR *jcr, struct CHKSUM *chksum) +int send_data(JCR *jcr, int stream, FF_PKT *ff_pkt, DIGEST *digest, DIGEST *signing_digest) { - uint64_t fileAddr = 0; /* file address */ + BSOCK *sd = jcr->store_bsock; + uint64_t fileAddr = 0; /* file address */ char *rbuf, *wbuf; - int rsize = jcr->buf_size; /* read buffer size */ + int rsize = jcr->buf_size; /* read buffer size */ POOLMEM *msgsave; +#ifdef FD_NO_SEND_TEST + return 1; +#endif msgsave = sd->msg; - rbuf = sd->msg; /* read buffer */ - wbuf = sd->msg; /* write buffer */ + rbuf = sd->msg; /* read buffer */ + wbuf = sd->msg; /* write buffer */ Dmsg1(300, "Saving data, type=%d\n", ff_pkt->type); @@ -550,11 +501,11 @@ int send_data(int stream, FF_PKT *ff_pkt, BSOCK *sd, JCR *jcr, struct CHKSUM *ch if (ff_pkt->flags & FO_GZIP) { if (ff_pkt->flags & FO_SPARSE) { - cbuf = (Bytef *)jcr->compress_buf + SPARSE_FADDR_SIZE; - max_compress_len = jcr->compress_buf_size - SPARSE_FADDR_SIZE; + cbuf = (Bytef *)jcr->compress_buf + SPARSE_FADDR_SIZE; + max_compress_len = jcr->compress_buf_size - SPARSE_FADDR_SIZE; } else { - cbuf = (Bytef *)jcr->compress_buf; - max_compress_len = jcr->compress_buf_size; /* set max length */ + cbuf = (Bytef *)jcr->compress_buf; + max_compress_len = jcr->compress_buf_size; /* set max length */ } wbuf = jcr->compress_buf; /* compressed output here */ } @@ -562,18 +513,18 @@ int send_data(int stream, FF_PKT *ff_pkt, BSOCK *sd, JCR *jcr, struct CHKSUM *ch /* * Send Data header to Storage daemon - * + * */ if (!bnet_fsend(sd, "%ld %d 0", jcr->JobFiles, stream)) { Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"), - bnet_strerror(sd)); + bnet_strerror(sd)); return 0; } Dmsg1(300, ">stored: datahdr %s\n", sd->msg); /* * Make space at beginning of buffer for fileAddr because this - * same buffer will be used for writing if compression if off. + * same buffer will be used for writing if compression if off. */ if (ff_pkt->flags & FO_SPARSE) { rbuf += SPARSE_FADDR_SIZE; @@ -587,6 +538,12 @@ int send_data(int stream, FF_PKT *ff_pkt, BSOCK *sd, JCR *jcr, struct CHKSUM *ch #endif } + /* a RAW device read on win32 only works if the buffer is a multiple of 512 */ +#ifdef HAVE_WIN32 + if (S_ISBLK(ff_pkt->statp.st_mode)) + rsize = (rsize/512) * 512; +#endif + /* * Read the file data */ @@ -595,65 +552,73 @@ int send_data(int stream, FF_PKT *ff_pkt, BSOCK *sd, JCR *jcr, struct CHKSUM *ch /* Check for sparse blocks */ if (ff_pkt->flags & FO_SPARSE) { - ser_declare; - if (sd->msglen == rsize && - (fileAddr+sd->msglen < (uint64_t)ff_pkt->statp.st_size)) { - sparseBlock = is_buf_zero(rbuf, rsize); - } - - ser_begin(wbuf, SPARSE_FADDR_SIZE); - ser_uint64(fileAddr); /* store fileAddr in begin of buffer */ + ser_declare; + if (sd->msglen == rsize && + fileAddr+sd->msglen < (uint64_t)ff_pkt->statp.st_size || + ((ff_pkt->type == FT_RAW || ff_pkt->type == FT_FIFO) && + (uint64_t)ff_pkt->statp.st_size == 0)) { + sparseBlock = is_buf_zero(rbuf, rsize); + } + + ser_begin(wbuf, SPARSE_FADDR_SIZE); + ser_uint64(fileAddr); /* store fileAddr in begin of buffer */ } - jcr->ReadBytes += sd->msglen; /* count bytes read */ + jcr->ReadBytes += sd->msglen; /* count bytes read */ fileAddr += sd->msglen; /* Update checksum if requested */ - chksum_update(chksum, (unsigned char *)rbuf, sd->msglen); + if (digest) { + crypto_digest_update(digest, rbuf, sd->msglen); + } + + /* Update signing digest if requested */ + if (signing_digest) { + crypto_digest_update(signing_digest, rbuf, sd->msglen); + } #ifdef HAVE_LIBZ /* Do compression if turned on */ if (!sparseBlock && ff_pkt->flags & FO_GZIP) { - int zstat; - compress_len = max_compress_len; + int zstat; + compress_len = max_compress_len; Dmsg4(400, "cbuf=0x%x len=%u rbuf=0x%x len=%u\n", cbuf, compress_len, - rbuf, sd->msglen); - /* NOTE! This call modifies compress_len !!! */ - if ((zstat=compress2((Bytef *)cbuf, &compress_len, - (const Bytef *)rbuf, (uLong)sd->msglen, - ff_pkt->GZIP_level)) != Z_OK) { + rbuf, sd->msglen); + /* NOTE! This call modifies compress_len !!! */ + if ((zstat=compress2((Bytef *)cbuf, &compress_len, + (const Bytef *)rbuf, (uLong)sd->msglen, + ff_pkt->GZIP_level)) != Z_OK) { Jmsg(jcr, M_FATAL, 0, _("Compression error: %d\n"), zstat); - sd->msg = msgsave; - sd->msglen = 0; - set_jcr_job_status(jcr, JS_ErrorTerminated); - return 0; - } + sd->msg = msgsave; + sd->msglen = 0; + set_jcr_job_status(jcr, JS_ErrorTerminated); + return 0; + } Dmsg2(400, "compressed len=%d uncompressed len=%d\n", - compress_len, sd->msglen); + compress_len, sd->msglen); - sd->msglen = compress_len; /* set compressed length */ + sd->msglen = compress_len; /* set compressed length */ } #endif /* Send the buffer to the Storage daemon */ if (!sparseBlock) { - if (ff_pkt->flags & FO_SPARSE) { - sd->msglen += SPARSE_FADDR_SIZE; /* include fileAddr in size */ - } - sd->msg = wbuf; /* set correct write buffer */ - if (!bnet_send(sd)) { - berrno be; - Jmsg2(jcr, M_FATAL, 0, _("Network send error %d to SD. ERR=%s\n"), - sd->msglen, bnet_strerror(sd)); - sd->msg = msgsave; /* restore bnet buffer */ - sd->msglen = 0; - return 0; - } + if (ff_pkt->flags & FO_SPARSE) { + sd->msglen += SPARSE_FADDR_SIZE; /* include fileAddr in size */ + } + sd->msg = wbuf; /* set correct write buffer */ + if (!bnet_send(sd)) { + Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"), + bnet_strerror(sd)); + sd->msg = msgsave; /* restore bnet buffer */ + sd->msglen = 0; + return 0; + } } Dmsg1(130, "Send data to SD len=%d\n", sd->msglen); - /* #endif */ - jcr->JobBytes += sd->msglen; /* count bytes saved possibly compressed */ - sd->msg = msgsave; /* restore read buffer */ + /* #endif */ + jcr->JobBytes += sd->msglen; /* count bytes saved possibly compressed */ + sd->msg = msgsave; /* restore read buffer */ } /* end while read file data */ @@ -661,14 +626,146 @@ int send_data(int stream, FF_PKT *ff_pkt, BSOCK *sd, JCR *jcr, struct CHKSUM *ch if (sd->msglen < 0) { berrno be; Jmsg(jcr, M_ERROR, 0, _("Read error on file %s. ERR=%s\n"), - ff_pkt->fname, be.strerror(ff_pkt->bfd.berrno)); + ff_pkt->fname, be.strerror(ff_pkt->bfd.berrno)); + if (jcr->Errors++ > 1000) { /* insanity check */ + Jmsg(jcr, M_FATAL, 0, _("Too many errors.\n")); + } + } - if (!bnet_sig(sd, BNET_EOD)) { /* indicate end of file data */ + if (!bnet_sig(sd, BNET_EOD)) { /* indicate end of file data */ Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"), - bnet_strerror(sd)); + bnet_strerror(sd)); return 0; } return 1; } + +/* + * Read and send an ACL for the last encountered file. + */ +static bool read_and_send_acl(JCR *jcr, int acltype, int stream) +{ +#ifdef HAVE_ACL + BSOCK *sd = jcr->store_bsock; + POOLMEM *msgsave; + int len; +#ifdef FD_NO_SEND_TEST + return true; +#endif + + len = bacl_get(jcr, acltype); + if (len < 0) { + Jmsg1(jcr, M_WARNING, 0, _("Error reading ACL of %s\n"), jcr->last_fname); + return true; + } + if (len == 0) { + return true; /* no ACL */ + } + + /* Send header */ + if (!bnet_fsend(sd, "%ld %d 0", jcr->JobFiles, stream)) { + Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"), + bnet_strerror(sd)); + return false; + } + + /* Send the buffer to the storage deamon */ + Dmsg2(400, "Backing up ACL type 0x%2x <%s>\n", acltype, jcr->acl_text); + msgsave = sd->msg; + sd->msg = jcr->acl_text; + sd->msglen = len + 1; + if (!bnet_send(sd)) { + sd->msg = msgsave; + sd->msglen = 0; + Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"), + bnet_strerror(sd)); + return false; + } + + jcr->JobBytes += sd->msglen; + sd->msg = msgsave; + if (!bnet_sig(sd, BNET_EOD)) { + Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"), + bnet_strerror(sd)); + return false; + } + + Dmsg1(200, "ACL of file: %s successfully backed up!\n", jcr->last_fname); +#endif + return true; +} + +static bool encode_and_send_attributes(JCR *jcr, FF_PKT *ff_pkt, int &data_stream) +{ + BSOCK *sd = jcr->store_bsock; + char attribs[MAXSTRING]; + char attribsEx[MAXSTRING]; + int attr_stream; + int stat; +#ifdef FD_NO_SEND_TEST + return true; +#endif + + /* Find what data stream we will use, then encode the attributes */ + data_stream = select_data_stream(ff_pkt); + encode_stat(attribs, ff_pkt, data_stream); + + /* Now possibly extend the attributes */ + attr_stream = encode_attribsEx(jcr, attribsEx, ff_pkt); + + Dmsg3(300, "File %s\nattribs=%s\nattribsEx=%s\n", ff_pkt->fname, attribs, attribsEx); + + P(jcr->mutex); + jcr->JobFiles++; /* increment number of files sent */ + ff_pkt->FileIndex = jcr->JobFiles; /* return FileIndex */ + pm_strcpy(jcr->last_fname, ff_pkt->fname); + V(jcr->mutex); + + /* + * Send Attributes header to Storage daemon + * + */ + if (!bnet_fsend(sd, "%ld %d 0", jcr->JobFiles, attr_stream)) { + Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"), + bnet_strerror(sd)); + return false; + } + Dmsg1(300, ">stored: attrhdr %s\n", sd->msg); + + /* + * Send file attributes to Storage daemon + * File_index + * File type + * Filename (full path) + * Encoded attributes + * Link name (if type==FT_LNK or FT_LNKSAVED) + * Encoded extended-attributes (for Win32) + * + * For a directory, link is the same as fname, but with trailing + * slash. For a linked file, link is the link. + */ + if (ff_pkt->type == FT_LNK || ff_pkt->type == FT_LNKSAVED) { + Dmsg2(300, "Link %s to %s\n", ff_pkt->fname, ff_pkt->link); + stat = bnet_fsend(sd, "%ld %d %s%c%s%c%s%c%s%c", jcr->JobFiles, + ff_pkt->type, ff_pkt->fname, 0, attribs, 0, ff_pkt->link, 0, + attribsEx, 0); + } else if (ff_pkt->type == FT_DIREND) { + /* Here link is the canonical filename (i.e. with trailing slash) */ + stat = bnet_fsend(sd, "%ld %d %s%c%s%c%c%s%c", jcr->JobFiles, + ff_pkt->type, ff_pkt->link, 0, attribs, 0, 0, attribsEx, 0); + } else { + stat = bnet_fsend(sd, "%ld %d %s%c%s%c%c%s%c", jcr->JobFiles, + ff_pkt->type, ff_pkt->fname, 0, attribs, 0, 0, attribsEx, 0); + } + + Dmsg2(300, ">stored: attr len=%d: %s\n", sd->msglen, sd->msg); + if (!stat) { + Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"), + bnet_strerror(sd)); + return false; + } + bnet_sig(sd, BNET_EOD); /* indicate end of attributes data */ + return true; +}