/*
Bacula® - The Network Backup Solution
- Copyright (C) 2000-2009 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.
* to do the backup.
* When the File daemon finishes the job, update the DB.
*
- * Version $Id$
*/
#include "bacula.h"
#include "ua.h"
/* Commands sent to File daemon */
-static char backupcmd[] = "backup\n";
+static char backupcmd[] = "backup FileIndex=%ld\n";
static char storaddr[] = "storage address=%s port=%d ssl=%d\n";
/* Responses received from File daemon */
bool do_backup_init(JCR *jcr)
{
- if (jcr->getJobLevel() == L_VIRTUAL_FULL) {
+ if (jcr->is_JobLevel(L_VIRTUAL_FULL)) {
return do_vbackup_init(jcr);
}
free_rstorage(jcr); /* we don't read so release */
}
/*
- * Foreach files in currrent list, send "/path/fname\0LStat\0MD5" to FD
+ * Foreach files in currrent list, send "/path/fname\0LStat\0MD5\0Delta" to FD
+ * row[0]=Path, row[1]=Filename, row[2]=FileIndex
+ * row[3]=JobId row[4]=LStat row[5]=MarkId row[6]=MD5
*/
static int accurate_list_handler(void *ctx, int num_fields, char **row)
{
return 1;
}
- if (row[2] == 0) { /* discard when file_index == 0 */
+ if (row[2][0] == '0') { /* discard when file_index == 0 */
return 0;
}
/* sending with checksum */
if (jcr->use_accurate_chksum
- && num_fields == 6
- && row[5][0] /* skip checksum = '0' */
- && row[5][1])
+ && num_fields == 7
+ && row[6][0] /* skip checksum = '0' */
+ && row[6][1])
{
- jcr->file_bsock->fsend("%s%s%c%s%c%s",
- row[0], row[1], 0, row[4], 0, row[5]);
+ jcr->file_bsock->fsend("%s%s%c%s%c%s%c%s",
+ row[0], row[1], 0, row[4], 0, row[6], 0, row[5]);
} else {
- jcr->file_bsock->fsend("%s%s%c%s",
- row[0], row[1], 0, row[4]);
+ jcr->file_bsock->fsend("%s%s%c%s%c%c%s",
+ row[0], row[1], 0, row[4], 0, 0, row[5]);
}
return 0;
}
have_basejob_option = in_block = jcr->HasBase;
break;
case 'C': /* Accurate keyword */
- in_block = (jcr->getJobLevel() != L_FULL);
+ in_block = !jcr->is_JobLevel(L_FULL);
break;
case ':': /* End of keyword */
in_block = false;
/*
* Send current file list to FD
* DIR -> FD : accurate files=xxxx
- * DIR -> FD : /path/to/file\0Lstat\0MD5
- * DIR -> FD : /path/to/dir/\0Lstat\0MD5
+ * DIR -> FD : /path/to/file\0Lstat\0MD5\0Delta
+ * DIR -> FD : /path/to/dir/\0Lstat\0MD5\0Delta
* ...
* DIR -> FD : EOD
*/
bool send_accurate_current_files(JCR *jcr)
{
POOL_MEM buf;
- bool ret=true;
db_list_ctx jobids;
db_list_ctx nb;
+ char ed1[50];
- if (!jcr->accurate || job_canceled(jcr)) {
- return true;
- }
- /* In base level, no previous job is used */
- if (jcr->getJobLevel() == L_BASE) {
- return true;
- }
-
- if (jcr->getJobLevel() == L_FULL) {
- /* On Full mode, if no previous base job, no accurate things */
- if (!get_base_jobids(jcr, &jobids)) {
- goto bail_out;
+ /* For incomplete Jobs, we add our own id */
+ if (jcr->incomplete) {
+ edit_int64(jcr->JobId, ed1);
+ jobids.add(ed1);
+ } else {
+ if (!jcr->accurate || job_canceled(jcr)) {
+ return true;
}
- jcr->HasBase = true;
- Jmsg(jcr, M_INFO, 0, _("Using BaseJobId(s): %s\n"), jobids.list);
+ /* In base level, no previous job is used */
+ if (jcr->is_JobLevel(L_BASE)) {
+ return true;
+ }
+
+ if (jcr->is_JobLevel(L_FULL)) {
+ /* On Full mode, if no previous base job, no accurate things */
+ if (!get_base_jobids(jcr, &jobids)) {
+ return true;
+ }
+ jcr->HasBase = true;
+ Jmsg(jcr, M_INFO, 0, _("Using BaseJobId(s): %s\n"), jobids.list);
- } else {
- /* For Incr/Diff level, we search for older jobs */
- db_accurate_get_jobids(jcr, jcr->db, &jcr->jr, &jobids);
-
- /* We are in Incr/Diff, but no Full to build the accurate list... */
- if (jobids.count == 0) {
- ret=false;
- Jmsg(jcr, M_FATAL, 0, _("Cannot find previous jobids.\n"));
- goto bail_out;
+ } else {
+ /* For Incr/Diff level, we search for older jobs */
+ db_accurate_get_jobids(jcr, jcr->db, &jcr->jr, &jobids);
+
+ /* We are in Incr/Diff, but no Full to build the accurate list... */
+ if (jobids.count == 0) {
+ Jmsg(jcr, M_FATAL, 0, _("Cannot find previous jobids.\n"));
+ return false; /* fail */
+ }
}
}
if (!db_open_batch_connexion(jcr, jcr->db)) {
Jmsg0(jcr, M_FATAL, 0, "Can't get batch sql connexion");
- return false;
+ return false; /* Fail */
}
if (jcr->HasBase) {
jcr->nb_base_files = str_to_int64(nb.list);
db_create_base_file_list(jcr, jcr->db, jobids.list);
- db_get_base_file_list(jcr, jcr->db,
+ db_get_base_file_list(jcr, jcr->db, jcr->use_accurate_chksum,
accurate_list_handler, (void *)jcr);
} else {
- db_get_file_list(jcr, jcr->db_batch, jobids.list,
+ db_get_file_list(jcr, jcr->db_batch,
+ jobids.list, jcr->use_accurate_chksum, false /* no delta */,
accurate_list_handler, (void *)jcr);
}
- /* TODO: close the batch connexion ? (can be used very soon) */
+ /* TODO: close the batch connection ? (can be used very soon) */
jcr->file_bsock->signal(BNET_EOD);
-
-bail_out:
- return ret;
+ return true;
}
/*
BSOCK *fd;
STORE *store;
char ed1[100];
+ db_int64_ctx job;
+ POOL_MEM buf;
- if (jcr->getJobLevel() == L_VIRTUAL_FULL) {
+ if (jcr->is_JobLevel(L_VIRTUAL_FULL)) {
return do_vbackup(jcr);
}
return false;
}
+ /* For incomplete Jobs, we add our own id */
+ if (jcr->incomplete) {
+ edit_int64(jcr->JobId, ed1);
+ Mmsg(buf, "SELECT max(FileIndex) FROM File WHERE JobId=%s", ed1);
+ if (!db_sql_query(jcr->db, buf.c_str(), db_int64_handler, &job)) {
+ Jmsg(jcr, M_FATAL, 0, "%s", db_strerror(jcr->db));
+ return false;
+ }
+ jcr->JobFiles = job.value;
+ Mmsg(buf, "SELECT VolSessionId FROM Job WHERE JobId=%s", ed1);
+ if (!db_sql_query(jcr->db, buf.c_str(), db_int64_handler, &job)) {
+ Jmsg(jcr, M_FATAL, 0, "%s", db_strerror(jcr->db));
+ return false;
+ }
+ jcr->VolSessionId = job.value;
+ Mmsg(buf, "SELECT VolSessionTime FROM Job WHERE JobId=%s", ed1);
+ if (!db_sql_query(jcr->db, buf.c_str(), db_int64_handler, &job)) {
+ Jmsg(jcr, M_FATAL, 0, "%s", db_strerror(jcr->db));
+ return false;
+ }
+ jcr->VolSessionTime = job.value;
+ Dmsg4(100, "JobId=%s JobFiles=%ld VolSessionId=%ld VolSessionTime=%ld\n", ed1,
+ jcr->JobFiles, jcr->VolSessionId, jcr->VolSessionTime);
+ }
+
/*
* Open a message channel connection with the Storage
* daemon. This is to let him know that our client
* to avoid two threads from using the BSOCK structure at
* the same time.
*/
- if (!bnet_fsend(jcr->store_bsock, "run")) {
+ if (!jcr->store_bsock->fsend("run")) {
return false;
}
* all files to FD.
*/
if (!send_accurate_current_files(jcr)) {
- goto bail_out;
+ goto bail_out; /* error */
}
/* Send backup command */
- fd->fsend(backupcmd);
+ fd->fsend(backupcmd, jcr->JobFiles);
+ Dmsg1(100, ">filed: %s", fd->msg);
if (!response(jcr, fd, OKbackup, "backup", DISPLAY_ERROR)) {
goto bail_out;
}
stat = wait_for_job_termination(jcr);
db_write_batch_file_records(jcr); /* used by bulk batch file insert */
- if (jcr->HasBase &&
- !db_commit_base_file_attributes_record(jcr, jcr->db))
- {
- Jmsg(jcr, M_FATAL, 0, "%s", db_strerror(jcr->db));
+ if (jcr->HasBase && !db_commit_base_file_attributes_record(jcr, jcr->db)) {
+ Jmsg(jcr, M_FATAL, 0, "%s", db_strerror(jcr->db));
}
if (stat == JS_Terminated) {
fd->signal(BNET_TERMINATE); /* tell Client we are terminating */
}
- /* Force cancel in SD if failing */
- if (job_canceled(jcr) || !fd_ok) {
+ /*
+ * Force cancel in SD if failing, but not for Incomplete jobs
+ * so that we let the SD despool.
+ */
+ if (jcr->is_canceled() || !fd_ok) {
cancel_storage_daemon_job(jcr);
}
utime_t RunTime;
POOL_MEM base_info;
- if (jcr->getJobLevel() == L_VIRTUAL_FULL) {
+ if (jcr->is_JobLevel(L_VIRTUAL_FULL)) {
vbackup_cleanup(jcr, TermCode);
return;
}
term_msg = _("Backup OK");
}
break;
+ case JS_Incomplete:
+ term_msg = _("Backup failed -- incomplete");
+ break;
case JS_Warnings:
term_msg = _("Backup OK -- with warnings");
break;
fd = bpipe ? bpipe->wfd : NULL;
} else {
/* ***FIXME*** handle BASE */
- fd = fopen(fname, jcr->getJobLevel()==L_FULL?"w+b":"a+b");
+ fd = fopen(fname, jcr->is_JobLevel(L_FULL)?"w+b":"a+b");
}
if (fd) {
VolCount = db_get_job_volume_parameters(jcr, jcr->db, jcr->JobId,