/*
Bacula® - The Network Backup Solution
- Copyright (C) 2000-2010 Free Software Foundation Europe e.V.
+ Copyright (C) 2000-2011 Free Software Foundation Europe e.V.
The main author of Bacula is Kern Sibbald, with contributions from
many others, a complete list can be found in the file AUTHORS.
This program is Free Software; you can redistribute it and/or
- modify it under the terms of version two of the GNU General Public
+ modify it under the terms of version three of the GNU Affero General Public
License as published by the Free Software Foundation and included
in the file LICENSE.
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
+ You should have received a copy of the GNU Affero General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301, USA.
#include "bacula.h"
#include "filed.h"
+#include "ch.h"
#ifdef HAVE_DARWIN_OS
const bool have_darwin_os = true;
sd = jcr->store_bsock;
- set_jcr_job_status(jcr, JS_Running);
+ jcr->setJobStatus(JS_Running);
Dmsg1(300, "bfiled: opened data connection %d to stored\n", sd->m_fd);
buf_size = 0; /* use default */
}
if (!sd->set_buffer_size(buf_size, BNET_SETBUF_WRITE)) {
- set_jcr_job_status(jcr, JS_ErrorTerminated);
+ jcr->setJobStatus(JS_ErrorTerminated);
Jmsg(jcr, M_FATAL, 0, _("Cannot set buffer size FD->SD.\n"));
return false;
}
* Note, we adjust the read size to be smaller so that the
* same output buffer can be used without growing it.
*
+ * For LZO1X compression the recommended value is :
+ * output_block_size = input_block_size + (input_block_size / 16) + 64 + 3 + sizeof(comp_stream_header)
+ *
* The zlib compression workset is initialized here to minimize
* the "per file" load. The jcr member is only set, if the init
* was successful.
+ *
+ * For the same reason, lzo compression is initialized here.
*/
+#ifdef HAVE_LZO
+ 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);
+ jcr->compress_buf = get_memory(jcr->compress_buf_size);
+#else
jcr->compress_buf_size = jcr->buf_size + ((jcr->buf_size+999) / 1000) + 30;
jcr->compress_buf = get_memory(jcr->compress_buf_size);
+#endif
#ifdef HAVE_LIBZ
z_stream *pZlibStream = (z_stream*)malloc(sizeof(z_stream));
}
#endif
+#ifdef HAVE_LZO
+ lzo_voidp pLzoMem = (lzo_voidp) malloc(LZO1X_1_MEM_COMPRESS);
+ if (pLzoMem) {
+ if (lzo_init() == LZO_E_OK) {
+ jcr->LZO_compress_workset = pLzoMem;
+ } else {
+ free (pLzoMem);
+ }
+ }
+#endif
+
if (!crypto_session_start(jcr)) {
return false;
}
set_find_options((FF_PKT *)jcr->ff, jcr->incremental, jcr->mtime);
- /** in accurate mode, we overwrite the find_one check function */
+ /** in accurate mode, we overload the find_one check function */
if (jcr->accurate) {
set_find_changed_function((FF_PKT *)jcr->ff, accurate_check_file);
}
/** Subroutine save_file() is called for each file */
if (!find_files(jcr, (FF_PKT *)jcr->ff, save_file, plugin_save)) {
ok = false; /* error */
- set_jcr_job_status(jcr, JS_ErrorTerminated);
+ jcr->setJobStatus(JS_ErrorTerminated);
}
if (have_acl && jcr->acl_data->nr_errors > 0) {
- Jmsg(jcr, M_ERROR, 0, _("Encountered %ld acl errors while doing backup\n"),
+ Jmsg(jcr, M_WARNING, 0, _("Encountered %ld acl errors while doing backup\n"),
jcr->acl_data->nr_errors);
}
if (have_xattr && jcr->xattr_data->nr_errors > 0) {
- Jmsg(jcr, M_ERROR, 0, _("Encountered %ld xattr errors while doing backup\n"),
+ Jmsg(jcr, M_WARNING, 0, _("Encountered %ld xattr errors while doing backup\n"),
jcr->xattr_data->nr_errors);
}
free (jcr->pZLIB_compress_workset);
jcr->pZLIB_compress_workset = NULL;
}
+ if (jcr->LZO_compress_workset) {
+ free (jcr->LZO_compress_workset);
+ jcr->LZO_compress_workset = NULL;
+ }
+
crypto_session_end(jcr);
#endif
BSOCK *sd = jcr->store_bsock;
- if (jcr->is_job_canceled()) {
+ if (jcr->is_canceled() || jcr->is_incomplete()) {
return 0;
}
case FT_NOFSCHG:
/* Suppress message for /dev filesystems */
if (!is_in_fileset(ff_pkt)) {
- Jmsg(jcr, M_INFO, 1, _(" %s is a different filesystem. Will not descend from %s into %s\n"),
- ff_pkt->fname, ff_pkt->top_fname, ff_pkt->fname);
+ Jmsg(jcr, M_INFO, 1, _(" %s is a different filesystem. Will not descend from %s into it.\n"),
+ ff_pkt->fname, ff_pkt->top_fname);
}
ff_pkt->type = FT_DIREND; /* Backup only the directory entry */
break;
ff_pkt->fname);
break;
case FT_REPARSE:
+ case FT_JUNCTION:
case FT_DIREND:
Dmsg1(130, "FT_DIREND: %s\n", ff_pkt->link);
break;
do_read = ff_pkt->statp.st_size > 0;
#endif
} else if (ff_pkt->type == FT_RAW || ff_pkt->type == FT_FIFO ||
- ff_pkt->type == FT_REPARSE ||
+ ff_pkt->type == FT_REPARSE || ff_pkt->type == FT_JUNCTION ||
(!is_portable_backup(&ff_pkt->bfd) && ff_pkt->type == FT_DIREND)) {
do_read = true;
}
tid = NULL;
}
int noatime = ff_pkt->flags & FO_NOATIME ? O_NOATIME : 0;
- ff_pkt->bfd.reparse_point = ff_pkt->type == FT_REPARSE;
+ ff_pkt->bfd.reparse_point = (ff_pkt->type == FT_REPARSE ||
+ ff_pkt->type == FT_JUNCTION);
if (bopen(&ff_pkt->bfd, ff_pkt->fname, O_RDONLY | O_BINARY | noatime, 0) < 0) {
ff_pkt->ff_errno = errno;
berrno be;
goto good_rtn;
}
flags = ff_pkt->flags;
- ff_pkt->flags &= ~(FO_GZIP|FO_SPARSE);
+ ff_pkt->flags &= ~(FO_COMPRESS|FO_SPARSE|FO_OFFSETS);
if (flags & FO_ENCRYPT) {
rsrc_stream = STREAM_ENCRYPTED_MACOS_FORK_DATA;
} else {
* print the error message set by the lower level routine in jcr->errmsg.
*/
if (jcr->acl_data->nr_errors < ACL_REPORT_ERR_MAX_PER_JOB) {
- Jmsg(jcr, M_ERROR, 0, "%s", jcr->errmsg);
+ Jmsg(jcr, M_WARNING, 0, "%s", jcr->errmsg);
}
jcr->acl_data->nr_errors++;
break;
* print the error message set by the lower level routine in jcr->errmsg.
*/
if (jcr->xattr_data->nr_errors < XATTR_REPORT_ERR_MAX_PER_JOB) {
- Jmsg(jcr, M_ERROR, 0, "%s", jcr->errmsg);
+ Jmsg(jcr, M_WARNING, 0, "%s", jcr->errmsg);
}
jcr->xattr_data->nr_errors++;
break;
goto bail_out;
}
+ /* Keep the checksum if this file is a hardlink */
+ if (ff_pkt->linked) {
+ ff_pkt_set_link_digest(ff_pkt, digest_stream, sd->msg, size);
+ }
+
sd->msglen = size;
sd->send();
sd->signal(BNET_EOD); /* end of checksum */
}
+ /* Check if original file has a digest, and send it */
+ if (ff_pkt->type == FT_LNKSAVED && ff_pkt->digest) {
+ Dmsg2(300, "Link %s digest %d\n", ff_pkt->fname, ff_pkt->digest_len);
+ sd->fsend("%ld %d 0", jcr->JobFiles, ff_pkt->digest_stream);
+
+ sd->msg = check_pool_memory_size(sd->msg, ff_pkt->digest_len);
+ memcpy(sd->msg, ff_pkt->digest, ff_pkt->digest_len);
+ sd->msglen = ff_pkt->digest_len;
+ sd->send();
+
+ sd->signal(BNET_EOD); /* end of hardlink record */
+ }
+
good_rtn:
- rtnstat = 1; /* good return */
+ rtnstat = jcr->is_canceled() ? 0 : 1; /* good return if not canceled */
bail_out:
+ if (jcr->is_incomplete()) {
+ rtnstat = 0;
+ }
if (ff_pkt->cmd_plugin && plugin_started) {
send_plugin_name(jcr, sd, false); /* signal end of plugin data */
}
Dmsg1(300, "Saving data, type=%d\n", ff_pkt->type);
-#ifdef HAVE_LIBZ
+#if defined(HAVE_LIBZ) || defined(HAVE_LZO)
uLong compress_len = 0;
uLong max_compress_len = 0;
const Bytef *cbuf = NULL;
+ #ifdef HAVE_LIBZ
int zstat;
- 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;
+ if ((ff_pkt->flags & FO_COMPRESS) && ff_pkt->Compress_algo == COMPRESS_GZIP) {
+ if ((ff_pkt->flags & FO_SPARSE) || (ff_pkt->flags & FO_OFFSETS)) {
+ cbuf = (Bytef *)jcr->compress_buf + OFFSET_FADDR_SIZE;
+ max_compress_len = jcr->compress_buf_size - OFFSET_FADDR_SIZE;
} else {
cbuf = (Bytef *)jcr->compress_buf;
max_compress_len = jcr->compress_buf_size; /* set max length */
if (((z_stream*)jcr->pZLIB_compress_workset)->total_in == 0) {
/** set gzip compression level - must be done per file */
if ((zstat=deflateParams((z_stream*)jcr->pZLIB_compress_workset,
- ff_pkt->GZIP_level, Z_DEFAULT_STRATEGY)) != Z_OK) {
+ ff_pkt->Compress_level, Z_DEFAULT_STRATEGY)) != Z_OK) {
Jmsg(jcr, M_FATAL, 0, _("Compression deflateParams error: %d\n"), zstat);
- set_jcr_job_status(jcr, JS_ErrorTerminated);
+ jcr->setJobStatus(JS_ErrorTerminated);
goto err;
}
}
}
+ #endif
+ #ifdef HAVE_LZO
+ Bytef *cbuf2;
+ int lzores;
+ comp_stream_header ch;
+
+ memset(&ch, 0, sizeof(comp_stream_header));
+ cbuf2 = NULL;
+
+ if ((ff_pkt->flags & FO_COMPRESS) && ff_pkt->Compress_algo == COMPRESS_LZO1X) {
+ if ((ff_pkt->flags & FO_SPARSE) || (ff_pkt->flags & FO_OFFSETS)) {
+ cbuf = (Bytef *)jcr->compress_buf + OFFSET_FADDR_SIZE;
+ cbuf2 = (Bytef *)jcr->compress_buf + OFFSET_FADDR_SIZE + sizeof(comp_stream_header);
+ max_compress_len = jcr->compress_buf_size - OFFSET_FADDR_SIZE;
+ } else {
+ cbuf = (Bytef *)jcr->compress_buf;
+ cbuf2 = (Bytef *)jcr->compress_buf + sizeof(comp_stream_header);
+ max_compress_len = jcr->compress_buf_size; /* set max length */
+ }
+ ch.magic = COMPRESS_LZO1X;
+ ch.version = COMP_HEAD_VERSION;
+ wbuf = jcr->compress_buf; /* compressed output here */
+ cipher_input = (uint8_t *)jcr->compress_buf; /* encrypt compressed data */
+ }
+ #endif
#else
const uint32_t max_compress_len = 0;
#endif
if (ff_pkt->flags & FO_ENCRYPT) {
- if (ff_pkt->flags & FO_SPARSE) {
- Jmsg0(jcr, M_FATAL, 0, _("Encrypting sparse data not supported.\n"));
+ if ((ff_pkt->flags & FO_SPARSE) || (ff_pkt->flags & FO_OFFSETS)) {
+ Jmsg0(jcr, M_FATAL, 0, _("Encrypting sparse or offset data not supported.\n"));
goto err;
}
/** Allocate the cipher context */
* Make space at beginning of buffer for fileAddr because this
* same buffer will be used for writing if compression is off.
*/
- if (ff_pkt->flags & FO_SPARSE) {
- rbuf += SPARSE_FADDR_SIZE;
- rsize -= SPARSE_FADDR_SIZE;
+ if ((ff_pkt->flags & FO_SPARSE) || (ff_pkt->flags & FO_OFFSETS)) {
+ rbuf += OFFSET_FADDR_SIZE;
+ rsize -= OFFSET_FADDR_SIZE;
#ifdef HAVE_FREEBSD_OS
/**
* To read FreeBSD partitions, the read size must be
}
if (!allZeros) {
/** Put file address as first data in buffer */
- ser_begin(wbuf, SPARSE_FADDR_SIZE);
+ ser_begin(wbuf, OFFSET_FADDR_SIZE);
ser_uint64(fileAddr); /* store fileAddr in begin of buffer */
}
fileAddr += sd->msglen; /* update file address */
if (allZeros) {
continue; /* skip block of zeros */
}
+ } else if (ff_pkt->flags & FO_OFFSETS) {
+ ser_declare;
+ ser_begin(wbuf, OFFSET_FADDR_SIZE);
+ ser_uint64(ff_pkt->bfd.offset); /* store offset in begin of buffer */
}
jcr->ReadBytes += sd->msglen; /* count bytes read */
#ifdef HAVE_LIBZ
/** Do compression if turned on */
- if (ff_pkt->flags & FO_GZIP && jcr->pZLIB_compress_workset) {
+ if (ff_pkt->flags & FO_COMPRESS && ff_pkt->Compress_algo == COMPRESS_GZIP && jcr->pZLIB_compress_workset) {
Dmsg3(400, "cbuf=0x%x rbuf=0x%x len=%u\n", cbuf, rbuf, sd->msglen);
((z_stream*)jcr->pZLIB_compress_workset)->next_in = (Bytef *)rbuf;
if ((zstat=deflate((z_stream*)jcr->pZLIB_compress_workset, Z_FINISH)) != Z_STREAM_END) {
Jmsg(jcr, M_FATAL, 0, _("Compression deflate error: %d\n"), zstat);
- set_jcr_job_status(jcr, JS_ErrorTerminated);
+ jcr->setJobStatus(JS_ErrorTerminated);
goto err;
}
compress_len = ((z_stream*)jcr->pZLIB_compress_workset)->total_out;
/** reset zlib stream to be able to begin from scratch again */
if ((zstat=deflateReset((z_stream*)jcr->pZLIB_compress_workset)) != Z_OK) {
Jmsg(jcr, M_FATAL, 0, _("Compression deflateReset error: %d\n"), zstat);
- set_jcr_job_status(jcr, JS_ErrorTerminated);
+ jcr->setJobStatus(JS_ErrorTerminated);
+ goto err;
+ }
+
+ Dmsg2(400, "GZIP compressed len=%d uncompressed len=%d\n", compress_len,
+ sd->msglen);
+
+ sd->msglen = compress_len; /* set compressed length */
+ cipher_input_len = compress_len;
+ }
+#endif
+#ifdef HAVE_LZO
+ /** Do compression if turned on */
+ if (ff_pkt->flags & FO_COMPRESS && ff_pkt->Compress_algo == COMPRESS_LZO1X && jcr->LZO_compress_workset) {
+ ser_declare;
+ ser_begin(cbuf, sizeof(comp_stream_header));
+
+ Dmsg3(400, "cbuf=0x%x rbuf=0x%x len=%u\n", cbuf, rbuf, sd->msglen);
+
+ lzores = lzo1x_1_compress((const unsigned char*)rbuf, sd->msglen, cbuf2, &compress_len, jcr->LZO_compress_workset);
+ if (lzores == LZO_E_OK && compress_len <= max_compress_len)
+ {
+ /* complete header */
+ ser_uint32(COMPRESS_LZO1X);
+ ser_uint32(compress_len);
+ ser_uint16(ch.level);
+ ser_uint16(ch.version);
+ } else {
+ /** this should NEVER happen */
+ Jmsg(jcr, M_FATAL, 0, _("Compression LZO error: %d\n"), lzores);
+ jcr->setJobStatus(JS_ErrorTerminated);
goto err;
}
- Dmsg2(400, "compressed len=%d uncompressed len=%d\n", compress_len,
+ Dmsg2(400, "LZO compressed len=%d uncompressed len=%d\n", compress_len,
sd->msglen);
+ compress_len += sizeof(comp_stream_header); /* add size of header */
sd->msglen = compress_len; /* set compressed length */
cipher_input_len = compress_len;
}
#endif
+
/**
* Note, here we prepend the current record length to the beginning
* of the encrypted data. This is because both sparse and compression
uint32_t initial_len = 0;
ser_declare;
- if (ff_pkt->flags & FO_SPARSE) {
- cipher_input_len += SPARSE_FADDR_SIZE;
+ if ((ff_pkt->flags & FO_SPARSE) || (ff_pkt->flags & FO_OFFSETS)) {
+ cipher_input_len += OFFSET_FADDR_SIZE;
}
/** Encrypt the length of the input block */
}
/* Send the buffer to the Storage daemon */
- if (ff_pkt->flags & FO_SPARSE) {
- sd->msglen += SPARSE_FADDR_SIZE; /* include fileAddr in size */
+ if ((ff_pkt->flags & FO_SPARSE) || (ff_pkt->flags & FO_OFFSETS)) {
+ sd->msglen += OFFSET_FADDR_SIZE; /* include fileAddr in size */
}
sd->msg = wbuf; /* set correct write buffer */
if (!sd->send()) {
int attr_stream;
int comp_len;
bool stat;
+ int hangup = get_hangup();
#ifdef FD_NO_SEND_TEST
return true;
#endif
Jmsg0(jcr, M_FATAL, 0, _("Invalid file flags, no supported data stream type.\n"));
return false;
}
- encode_stat(attribs, &ff_pkt->statp, ff_pkt->LinkFI, data_stream);
+ encode_stat(attribs, &ff_pkt->statp, sizeof(ff_pkt->statp), ff_pkt->LinkFI, data_stream);
/** Now possibly extend the attributes */
if (ff_pkt->type == FT_RESTORE_FIRST) {
pm_strcpy(jcr->last_fname, ff_pkt->fname);
jcr->unlock();
+ /* Debug code: check if we must hangup */
+ if (hangup && (jcr->JobFiles > (uint32_t)hangup)) {
+ jcr->setJobStatus(JS_Incomplete);
+ Jmsg1(jcr, M_FATAL, 0, "Debug hangup requested after %d files.\n", hangup);
+ set_hangup(0);
+ return false;
+ }
+
/**
* Send Attributes header to Storage daemon
* <file-index> <stream> <info>
*/
if (!sd->fsend("%ld %d 0", jcr->JobFiles, attr_stream)) {
- if (!jcr->is_job_canceled()) {
+ if (!jcr->is_canceled() && !jcr->is_incomplete()) {
Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
sd->bstrerror());
}
switch (ff_pkt->type) {
case FT_LNK:
case FT_LNKSAVED:
- Dmsg2(300, "Link %s to %s\n", ff_pkt->fname, ff_pkt->link);
- stat = sd->fsend("%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);
+ Dmsg3(300, "Link %d %s to %s\n", jcr->JobFiles, ff_pkt->fname, ff_pkt->link);
+ stat = sd->fsend("%ld %d %s%c%s%c%s%c%s%c%u%c", jcr->JobFiles,
+ ff_pkt->type, ff_pkt->fname, 0, attribs, 0,
+ ff_pkt->link, 0, attribsEx, 0, ff_pkt->delta_seq, 0);
break;
case FT_DIREND:
case FT_REPARSE:
+ case FT_JUNCTION:
/* Here link is the canonical filename (i.e. with trailing slash) */
- stat = sd->fsend("%ld %d %s%c%s%c%c%s%c", jcr->JobFiles,
- ff_pkt->type, ff_pkt->link, 0, attribs, 0, 0, attribsEx, 0);
+ stat = sd->fsend("%ld %d %s%c%s%c%c%s%c%u%c", jcr->JobFiles,
+ ff_pkt->type, ff_pkt->link, 0, attribs, 0, 0,
+ attribsEx, 0, ff_pkt->delta_seq, 0);
break;
case FT_RESTORE_FIRST:
comp_len = ff_pkt->object_len;
+ ff_pkt->object_compression = 0;
if (ff_pkt->object_len > 1000) {
/* Big object, compress it */
int stat;
}
Dmsg2(100, "Object compressed from %d to %d bytes\n", ff_pkt->object_len, comp_len);
}
- sd->msglen = Mmsg(sd->msg, "%d %d %d %d %d %d %s%c%s%c",
+ sd->msglen = Mmsg(sd->msg, "%d %d %d %d %d %d %s%c%s%c",
jcr->JobFiles, ff_pkt->type, ff_pkt->object_index,
comp_len, ff_pkt->object_len, ff_pkt->object_compression,
ff_pkt->fname, 0, ff_pkt->object_name, 0);
free_and_null_pool_memory(ff_pkt->object);
}
break;
+ case FT_REG:
+ stat = sd->fsend("%ld %d %s%c%s%c%c%s%c%d%c", jcr->JobFiles,
+ ff_pkt->type, ff_pkt->fname, 0, attribs, 0, 0, attribsEx, 0,
+ ff_pkt->delta_seq, 0);
+ break;
default:
- stat = sd->fsend("%ld %d %s%c%s%c%c%s%c", jcr->JobFiles,
- ff_pkt->type, ff_pkt->fname, 0, attribs, 0, 0, attribsEx, 0);
+ stat = sd->fsend("%ld %d %s%c%s%c%c%s%c%u%c", jcr->JobFiles,
+ ff_pkt->type, ff_pkt->fname, 0, attribs, 0, 0,
+ attribsEx, 0, ff_pkt->delta_seq, 0);
break;
}
if (ff_pkt->type != FT_DELETED) {
pm_strcpy(ff_pkt->link_save, ff_pkt->link);
Dmsg2(500, "strcpy link_save=%d link=%d\n", strlen(ff_pkt->link_save),
strlen(ff_pkt->link));
- sm_check(__FILE__, __LINE__, true);
+ Dsm_check(200);
}
/**
strcpy(ff_pkt->link, ff_pkt->link_save);
Dmsg2(500, "strcpy link=%d link_save=%d\n", strlen(ff_pkt->link),
strlen(ff_pkt->link_save));
- sm_check(__FILE__, __LINE__, true);
+ Dsm_check(200);
}
}
WCHAR *metadata = g_pVSSClient->GetMetadata();
if (metadata) {
FF_PKT *ff_pkt = jcr->ff;
- ff_pkt->fname = "job";
+ ff_pkt->fname = (char *)"job";
ff_pkt->type = FT_RESTORE_FIRST;
ff_pkt->LinkFI = 0;
- ff_pkt->object_name = "job_metadata.xml";
+ ff_pkt->object_name = (char *)"job_metadata.xml";
ff_pkt->object = (char *)metadata;
ff_pkt->object_len = (wcslen(metadata) + 1) * sizeof(WCHAR);
+ ff_pkt->object_index = (int)time(NULL);
save_file(jcr, ff_pkt, true);
}
}