1 Index: src/dird/fd_cmds.c
2 ===================================================================
3 --- src/dird/fd_cmds.c (révision 6443)
4 +++ src/dird/fd_cmds.c (copie de travail)
6 static char filesetcmd[] = "fileset%s\n"; /* set full fileset */
7 static char jobcmd[] = "JobId=%s Job=%s SDid=%u SDtime=%u Authorization=%s\n";
8 /* Note, mtime_only is not used here -- implemented as file option */
9 -static char levelcmd[] = "level = %s%s mtime_only=%d\n";
10 +static char levelcmd[] = "level = %s%s%s mtime_only=%d\n";
11 static char runscript[] = "Run OnSuccess=%u OnFailure=%u AbortOnError=%u When=%u Command=%s\n";
12 static char runbeforenow[]= "RunBeforeNow\n";
17 stime = str_to_utime(jcr->stime);
18 - fd->fsend(levelcmd, NT_("since_utime "), edit_uint64(stime, ed1), 0);
19 + fd->fsend(levelcmd, "", NT_("since_utime "), edit_uint64(stime, ed1), 0);
20 while (bget_dirmsg(fd) >= 0) { /* allow him to poll us to sync clocks */
21 Jmsg(jcr, M_INFO, 0, "%s\n", fd->msg);
24 bool send_level_command(JCR *jcr)
26 BSOCK *fd = jcr->file_bsock;
27 + const char *accurate=jcr->job->accurate?"accurate_":"";
29 * Send Level command to File daemon
31 switch (jcr->JobLevel) {
33 - fd->fsend(levelcmd, "base", " ", 0);
34 + fd->fsend(levelcmd, "", "base", " ", 0);
36 /* L_NONE is the console, sending something off to the FD */
39 - fd->fsend(levelcmd, "full", " ", 0);
40 + fd->fsend(levelcmd, "", "full", " ", 0);
43 - fd->fsend(levelcmd, "differential", " ", 0);
44 + fd->fsend(levelcmd, accurate, "differential", " ", 0);
48 - fd->fsend(levelcmd, "incremental", " ", 0);
49 + fd->fsend(levelcmd, accurate, "incremental", " ", 0);
53 Index: src/dird/backup.c
54 ===================================================================
55 --- src/dird/backup.c (révision 6443)
56 +++ src/dird/backup.c (copie de travail)
61 +static int accurate_list_handler(void *ctx, int num_fields, char **row)
63 + JCR *jcr = (JCR *)ctx;
65 + if (job_canceled(jcr)) {
69 + if (row[2] > 0) { /* discard when file_index == 0 */
70 + jcr->file_bsock->fsend("%s%s%c%s", row[0], row[1], 0, row[4]);
75 +bool send_accurate_current_files(JCR *jcr)
77 + char buf[MAXSTRING];
79 + if (jcr->accurate == false || job_canceled(jcr) || jcr->JobLevel == L_FULL) {
82 + POOLMEM *jobids = get_pool_memory(PM_FNAME);
83 + db_accurate_get_jobids(jcr, jcr->db, &jcr->jr, jobids);
86 + free_pool_memory(jobids);
87 + Jmsg(jcr, M_ERROR_TERM, 0, _("Cannot find previous jobids.\n"));
91 + /* to be able to allocate the right size for htable */
92 + POOLMEM *nb = get_pool_memory(PM_FNAME);
93 + bsnprintf(buf, sizeof(buf),
94 + "SELECT sum(JobFiles) FROM Job WHERE JobId IN (%s)",jobids);
95 + db_sql_query(jcr->db, buf, db_get_int_handler, nb);
96 + jcr->file_bsock->fsend("accurate files=%s\n", nb);
98 + db_get_file_list(jcr, jcr->db, jobids, accurate_list_handler, (void *)jcr);
100 + free_pool_memory(jobids);
101 + free_pool_memory(nb);
103 + jcr->file_bsock->signal(BNET_EOD);
104 + /* TODO: use response() ? */
110 * Do a backup of the specified FileSet
113 Jmsg(jcr, M_FATAL, 0, "%s", db_strerror(jcr->db));
117 + * If backup is in accurate mode, FD will send the list of
120 + if (!send_accurate_current_files(jcr)) {
124 /* Send backup command */
125 fd->fsend(backupcmd);
126 if (!response(jcr, fd, OKbackup, "backup", DISPLAY_ERROR)) {
128 /* Pickup Job termination data */
129 stat = wait_for_job_termination(jcr);
130 db_write_batch_file_records(jcr); /* used by bulk batch file insert */
132 if (stat == JS_Terminated) {
133 backup_cleanup(jcr, stat);
136 " Software Compression: %s\n"
140 " Volume name(s): %s\n"
141 " Volume Session Id: %d\n"
142 " Volume Session Time: %d\n"
144 edit_uint64_with_suffix(jcr->SDJobBytes, ec6),
147 - jcr->VSS?"yes":"no",
148 - jcr->Encrypt?"yes":"no",
149 + jcr->VSS?_("yes"):_("no"),
150 + jcr->Encrypt?_("yes"):_("no"),
151 + jcr->accurate?_("yes"):_("no"),
155 Index: src/dird/ua_restore.c
156 ===================================================================
157 --- src/dird/ua_restore.c (révision 6443)
158 +++ src/dird/ua_restore.c (copie de travail)
159 @@ -1006,7 +1006,6 @@
160 * For display purposes, the same JobId, with different volumes may
161 * appear more than once, however, we only insert it once.
165 tree.FileEstimate = 0;
166 if (get_next_jobid_from_list(&p, &JobId) > 0) {
167 @@ -1021,24 +1020,14 @@
168 tree.DeltaCount = rx->JobId/50; /* print 50 ticks */
171 - for (p=rx->JobIds; get_next_jobid_from_list(&p, &JobId) > 0; ) {
174 - if (JobId == last_JobId) {
175 - continue; /* eliminate duplicate JobIds */
177 - last_JobId = JobId;
178 - ua->info_msg(_("\nBuilding directory tree for JobId %s ... "),
179 - edit_int64(JobId, ed1));
182 - * Find files for this JobId and insert them in the tree
184 - Mmsg(rx->query, uar_sel_files, edit_int64(JobId, ed1));
185 - if (!db_sql_query(ua->db, rx->query, insert_tree_handler, (void *)&tree)) {
186 - ua->error_msg("%s", db_strerror(ua->db));
188 + ua->info_msg(_("\nBuilding directory tree for JobId(s) %s ... "),
191 + if (!db_get_file_list(ua->jcr, ua->db, rx->JobIds, insert_tree_handler, (void *)&tree)) {
192 + ua->error_msg("%s", db_strerror(ua->db));
195 if (tree.FileCount == 0) {
196 ua->send_msg(_("\nThere were no files inserted into the tree, so file selection\n"
197 "is not possible.Most likely your retention policy pruned the files\n"));
198 @@ -1056,26 +1045,13 @@
204 - ua->info_msg(_("\n1 Job, %s files inserted into the tree and marked for extraction.\n"),
205 - edit_uint64_with_commas(tree.FileCount, ec1));
208 - ua->info_msg(_("\n1 Job, %s files inserted into the tree.\n"),
209 - edit_uint64_with_commas(tree.FileCount, ec1));
212 + ua->info_msg(_("\n%s files inserted into the tree and marked for extraction.\n"),
213 + edit_uint64_with_commas(tree.FileCount, ec1));
215 + ua->info_msg(_("\n%s files inserted into the tree.\n"),
216 + edit_uint64_with_commas(tree.FileCount, ec1));
220 - ua->info_msg(_("\n%d Jobs, %s files inserted into the tree and marked for extraction.\n"),
221 - items, edit_uint64_with_commas(tree.FileCount, ec1));
224 - ua->info_msg(_("\n%d Jobs, %s files inserted into the tree.\n"),
225 - items, edit_uint64_with_commas(tree.FileCount, ec1));
229 if (find_arg(ua, NT_("done")) < 0) {
230 /* Let the user interact in selecting which files to restore */
231 Index: src/dird/inc_conf.c
232 ===================================================================
233 --- src/dird/inc_conf.c (révision 6443)
234 +++ src/dird/inc_conf.c (copie de travail)
236 * Items that are valid in an Options resource
238 static RES_ITEM options_items[] = {
239 + {"accurate", store_opts, {0}, 0, 0, 0},
240 {"compression", store_opts, {0}, 0, 0, 0},
241 {"signature", store_opts, {0}, 0, 0, 0},
242 {"verify", store_opts, {0}, 0, 0, 0},
254 * options given above.
256 static struct s_kw FS_option_kw[] = {
257 + {"accurate", INC_KW_ACCURATE},
258 {"compression", INC_KW_COMPRESSION},
259 {"signature", INC_KW_DIGEST},
260 {"encryption", INC_KW_ENCRYPTION},
262 {"no", INC_KW_ENHANCEDWILD, "0"},
263 {"yes", INC_KW_CHKCHANGES, "c"},
264 {"no", INC_KW_CHKCHANGES, "0"},
265 + {"yes", INC_KW_ACCURATE, "C"},
266 + {"no", INC_KW_ACCURATE, "0"},
270 Index: src/filed/backup.c
271 ===================================================================
272 --- src/filed/backup.c (révision 6443)
273 +++ src/filed/backup.c (copie de travail)
278 +#include "lib/htable.h"
280 /* Forward referenced functions */
281 int save_file(JCR *jcr, FF_PKT *ff_pkt, bool top_level);
283 static bool crypto_session_start(JCR *jcr);
284 static void crypto_session_end(JCR *jcr);
285 static bool crypto_session_send(JCR *jcr, BSOCK *sd);
286 +static bool encode_and_send_deleted_file(JCR *jcr, char *fname);
288 +typedef struct CurFile {
295 + * This function is called for each file seen in fileset.
297 + * If the file is skipped (saved=false), we will check if this
298 + * file have been backuped before. If not, we decide to backup it.
300 + * If the file have saved=true, we mark it as seen
303 +/* TODO: tweak verify code to use the same function */
304 +bool accurate_check_file(JCR *jcr, FF_PKT *ff_pkt, bool saved)
308 + struct stat statc; /* catalog stat */
309 + char *Opts_Digest = ff_pkt->VerifyOpts;
310 + char *fname = ff_pkt->fname;
315 + if (jcr->accurate == false || jcr->JobLevel == L_FULL) {
319 + if (ff_pkt->type == FT_DIREND || ff_pkt->type == FT_REPARSE || ff_pkt->type == FT_DIRNOCHG) {
320 + fname = ff_pkt->link;
323 + elt = (CurFile *) jcr->file_list->lookup(fname);
326 + // TODO: we must backup it !
327 + Dmsg1(1, "accurate %s = yes (not found)\n", fname);
331 + if (saved || *elt->lstat == '\0') {
332 + Dmsg1(1, "accurate %s = no (already seen)\n", fname);
333 + *elt->lstat = '\0';
337 + decode_stat(elt->lstat, &statc, &LinkFIc); /* decode catalog stat */
338 +// *do_Digest = CRYPTO_DIGEST_NONE;
340 + for (p=Opts_Digest; *p; p++) {
341 + char ed1[30], ed2[30];
343 + case 'i': /* compare INODEs */
344 + if (statc.st_ino != ff_pkt->statp.st_ino) {
345 + Jmsg(jcr, M_INFO, 0, _(" st_ino differ. Cat: %s File: %s\n"),
346 + edit_uint64((uint64_t)statc.st_ino, ed1),
347 + edit_uint64((uint64_t)ff_pkt->statp.st_ino, ed2));
351 + case 'p': /* permissions bits */
352 + if (statc.st_mode != ff_pkt->statp.st_mode) {
353 + Jmsg(jcr, M_INFO, 0, _(" st_mode differ. Cat: %x File: %x\n"),
354 + (uint32_t)statc.st_mode, (uint32_t)ff_pkt->statp.st_mode);
358 + case 'n': /* number of links */
359 + if (statc.st_nlink != ff_pkt->statp.st_nlink) {
360 + Jmsg(jcr, M_INFO, 0, _(" st_nlink differ. Cat: %d File: %d\n"),
361 + (uint32_t)statc.st_nlink, (uint32_t)ff_pkt->statp.st_nlink);
365 + case 'u': /* user id */
366 + if (statc.st_uid != ff_pkt->statp.st_uid) {
367 + Jmsg(jcr, M_INFO, 0, _(" st_uid differ. Cat: %u File: %u\n"),
368 + (uint32_t)statc.st_uid, (uint32_t)ff_pkt->statp.st_uid);
372 + case 'g': /* group id */
373 + if (statc.st_gid != ff_pkt->statp.st_gid) {
374 + Jmsg(jcr, M_INFO, 0, _(" st_gid differ. Cat: %u File: %u\n"),
375 + (uint32_t)statc.st_gid, (uint32_t)ff_pkt->statp.st_gid);
379 + case 's': /* size */
380 + if (statc.st_size != ff_pkt->statp.st_size) {
381 + Jmsg(jcr, M_INFO, 0, _(" st_size differ. Cat: %s File: %s\n"),
382 + edit_uint64((uint64_t)statc.st_size, ed1),
383 + edit_uint64((uint64_t)ff_pkt->statp.st_size, ed2));
387 + case 'a': /* access time */
388 + if (statc.st_atime != ff_pkt->statp.st_atime) {
389 + Jmsg(jcr, M_INFO, 0, _(" st_atime differs\n"));
394 + if (statc.st_mtime != ff_pkt->statp.st_mtime) {
395 + Jmsg(jcr, M_INFO, 0, _(" st_mtime differs\n"));
399 + case 'c': /* ctime */
400 + if (statc.st_ctime != ff_pkt->statp.st_ctime) {
401 + Jmsg(jcr, M_INFO, 0, _(" st_ctime differs\n"));
405 + case 'd': /* file size decrease */
406 + if (statc.st_size > ff_pkt->statp.st_size) {
407 + Jmsg(jcr, M_INFO, 0, _(" st_size decrease. Cat: %s File: %s\n"),
408 + edit_uint64((uint64_t)statc.st_size, ed1),
409 + edit_uint64((uint64_t)ff_pkt->statp.st_size, ed2));
413 + case '5': /* compare MD5 */
414 + Dmsg1(500, "set Do_MD5 for %s\n", ff_pkt->fname);
415 +// *do_Digest = CRYPTO_DIGEST_MD5;
417 + case '1': /* compare SHA1 */
418 +// *do_Digest = CRYPTO_DIGEST_SHA1;
426 + *elt->lstat = '\0'; /* mark it as seen */
427 + Dmsg2(1, "accurate %s = %i\n", fname, stat);
432 + * This function doesn't work very well with smartalloc
434 +int accurate_get_current_file_list_cmd(JCR *jcr)
436 + BSOCK *dir = jcr->dir_bsock;
441 + if (jcr->accurate == false || job_canceled(jcr) || jcr->JobLevel == L_FULL) {
445 + if (sscanf(dir->msg, "accurate files=%ld", &nb) != 1) {
446 + dir->fsend(_("2991 Bad accurate command\n"));
450 + Jmsg(jcr, M_INFO, 0, _("Getting Accurate informations.\n"));
452 + jcr->file_list = (htable *)malloc(sizeof(htable));
453 + jcr->file_list->init(elt, &elt->link, nb);
455 + /* get current files */
456 + while (dir->recv() >= 0) {
457 + len = strlen(dir->msg);
458 + if ((len+1) < dir->msglen) {
459 +// elt = (CurFile *)malloc(sizeof(CurFile));
460 +// elt->fname = (char *) malloc(dir->msglen+1);
462 + /* we store CurFile, fname and lstat in the same chunk */
463 + elt = (CurFile *)malloc(sizeof(CurFile)+dir->msglen+1);
464 + elt->fname = (char *) elt+sizeof(CurFile);
465 + memcpy(elt->fname, dir->msg, dir->msglen);
466 + elt->fname[dir->msglen]='\0';
467 + elt->lstat = elt->fname + len + 1;
468 + jcr->file_list->insert(elt->fname, elt);
469 + Dmsg2(1, "add fname=%s lstat=%s\n", elt->fname, elt->lstat);
473 +// jcr->file_list->stats();
474 + /* TODO: send a EOM ?
475 + dir->fsend("2000 OK accurate\n");
480 +bool accurate_send_deleted_list(JCR *jcr)
482 + if (jcr->accurate == false || jcr->JobLevel == L_FULL) {
486 + if (jcr->file_list == NULL) { /* TODO: bug ? */
491 + foreach_htable (elt, jcr->file_list) {
492 + if (*elt->lstat != '\0') {
493 + Dmsg2(1, "deleted fname=%s lstat=%s\n", elt->fname, elt->lstat);
494 + encode_and_send_deleted_file(jcr, elt->fname);
496 +// free(elt->fname);
498 + jcr->file_list->destroy(); /* TODO: clean htable when this function is not reached ? */
499 + free(jcr->file_list);
500 + jcr->file_list = NULL;
505 * Find all the requested files and send them
506 * to the Storage daemon.
511 // TODO landonf: Allow user to specify encryption algorithm
513 sd = jcr->store_bsock;
515 set_jcr_job_status(jcr, JS_Running);
518 jcr->compress_buf_size = jcr->buf_size + ((jcr->buf_size+999) / 1000) + 30;
519 jcr->compress_buf = get_memory(jcr->compress_buf_size);
523 z_stream *pZlibStream = (z_stream*)malloc(sizeof(z_stream));
526 ok = false; /* error */
527 set_jcr_job_status(jcr, JS_ErrorTerminated);
529 + Dmsg1(1, "jcr->accurate == %i\n", jcr->accurate);
531 + accurate_send_deleted_list(jcr); /* send deleted list to SD */
533 free_pool_memory(jcr->acl_text);
535 stop_heartbeat_monitor(jcr);
540 + /* TODO: in accurate mode, we have to change NOCHG attribute to FT_REG... */
541 +// if (!accurate_check_file(jcr, ff_pkt, false)) {
542 +// Jmsg(jcr, M_SKIPPED, 1, _(" Unchanged file skipped: %s\n"), ff_pkt->fname);
545 + accurate_check_file(jcr, ff_pkt, false);
546 Jmsg(jcr, M_SKIPPED, 1, _(" Unchanged file skipped: %s\n"), ff_pkt->fname);
549 + /* TODO: in accurate mode, we have to change NOCHG attribute to FT_REG... */
550 +// if (!accurate_check_file(jcr, ff_pkt, false)) {
551 +// Jmsg(jcr, M_NOTSAVED, 0, _(" Archive file not saved: %s\n"), ff_pkt->fname);
554 + accurate_check_file(jcr, ff_pkt, false);
555 Jmsg(jcr, M_NOTSAVED, 0, _(" Archive file not saved: %s\n"), ff_pkt->fname);
558 @@ -1118,6 +1350,9 @@
560 unstrip_path(ff_pkt);
562 + /* list backuped files */
563 + accurate_check_file(jcr, ff_pkt, true);
565 Dmsg2(300, ">stored: attr len=%d: %s\n", sd->msglen, sd->msg);
567 Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
568 @@ -1128,6 +1363,58 @@
572 +static bool encode_and_send_deleted_file(JCR *jcr, char *fname)
574 + BSOCK *sd = jcr->store_bsock;
578 +#ifdef FD_NO_SEND_TEST
586 + * Send Attributes header to Storage daemon
587 + * <file-index> <stream> <info>
589 + if (!sd->fsend("%ld %d 0", 0, STREAM_UNIX_ATTRIBUTES)) {
590 + Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
594 + Dmsg1(300, ">stored: attrhdr %s\n", sd->msg);
597 + * Send file attributes to Storage daemon
600 + * Filename (full path)
601 + * Encoded attributes
602 + * Link name (if type==FT_LNK or FT_LNKSAVED)
603 + * Encoded extended-attributes (for Win32)
605 + * For a directory, link is the same as fname, but with trailing
606 + * slash. For a linked file, link is the link.
608 + stat = sd->fsend("%ld %d %s%c%s%c%s%c%s%c",
610 + FT_NOSTAT /* FileType */,
611 + fname /* FileName */,
612 + 0, attribs, 0, 0, 0, attribsEx, 0);
614 + Dmsg2(300, ">stored: attr len=%d: %s\n", sd->msglen, sd->msg);
616 + Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
620 + sd->signal(BNET_EOD); /* indicate end of attributes data */
625 * Do in place strip of path
627 Index: src/filed/job.c
628 ===================================================================
629 --- src/filed/job.c (révision 6443)
630 +++ src/filed/job.c (copie de travail)
632 /* Imported functions */
633 extern int status_cmd(JCR *jcr);
634 extern int qstatus_cmd(JCR *jcr);
635 +extern int accurate_get_current_file_list_cmd(JCR *jcr);
637 /* Forward referenced functions */
638 static int backup_cmd(JCR *jcr);
640 {"RunBeforeJob", runbefore_cmd, 0},
641 {"RunAfterJob", runafter_cmd, 0},
642 {"Run", runscript_cmd, 0},
643 + {"accurate", accurate_get_current_file_list_cmd, 0},
644 {NULL, NULL} /* list terminator */
647 @@ -1087,6 +1089,9 @@
649 fo->flags |= FO_CHKCHANGES;
652 + fo->flags |= FO_ACCURATE;
655 Emsg1(M_ERROR, 0, _("Unknown include/exclude option: %c\n"), *p);
657 @@ -1195,6 +1200,9 @@
659 level = get_memory(dir->msglen+1);
660 Dmsg1(110, "level_cmd: %s", dir->msg);
661 + if (strstr(dir->msg, "accurate")) {
662 + jcr->accurate = true;
664 if (sscanf(dir->msg, "level = %s ", level) != 1) {
667 @@ -1204,14 +1212,14 @@
668 /* Full backup requested? */
669 } else if (strcmp(level, "full") == 0) {
670 jcr->JobLevel = L_FULL;
671 - } else if (strcmp(level, "differential") == 0) {
672 + } else if (strstr(level, "differential")) {
673 jcr->JobLevel = L_DIFFERENTIAL;
676 - } else if (strcmp(level, "incremental") == 0) {
677 + } else if (strstr(level, "incremental")) {
678 jcr->JobLevel = L_INCREMENTAL;
683 * We get his UTC since time, then sync the clocks and correct it
684 * to agree with our clock.
685 Index: src/filed/restore.c
686 ===================================================================
687 --- src/filed/restore.c (révision 6443)
688 +++ src/filed/restore.c (copie de travail)
693 + /* TODO: manage deleted files */
694 + if (file_index == 0) { /* deleted file */
699 * Unpack attributes and do sanity check them
701 Index: src/cats/protos.h
702 ===================================================================
703 --- src/cats/protos.h (révision 6443)
704 +++ src/cats/protos.h (copie de travail)
706 int db_get_client_record(JCR *jcr, B_DB *mdb, CLIENT_DBR *cdbr);
707 int db_get_counter_record(JCR *jcr, B_DB *mdb, COUNTER_DBR *cr);
708 bool db_get_query_dbids(JCR *jcr, B_DB *mdb, POOL_MEM &query, dbid_list &ids);
709 +bool db_get_file_list(JCR *jcr, B_DB *mdb, char *jobids, DB_RESULT_HANDLER *result_handler, void *ctx);
710 +bool db_accurate_get_jobids(JCR *jcr, B_DB *mdb, JOB_DBR *jr, POOLMEM *jobids);
711 +int db_get_int_handler(void *ctx, int num_fields, char **row);
715 Index: src/cats/sql_get.c
716 ===================================================================
717 --- src/cats/sql_get.c (révision 6443)
718 +++ src/cats/sql_get.c (copie de travail)
727 * Returns: false: on failure
728 @@ -1018,5 +1016,126 @@
732 +bool db_get_file_list(JCR *jcr, B_DB *mdb, char *jobids,
733 + DB_RESULT_HANDLER *result_handler, void *ctx)
735 + if (*jobids == 0) {
737 + Mmsg(mdb->errmsg, _("ERR=JobIds are empty\n"));
742 + POOL_MEM buf (PM_MESSAGE);
745 + "SELECT Path.Path, Filename.Name, File.FileIndex, File.JobId, File.LStat "
747 + "SELECT max(FileId) as FileId, PathId, FilenameId "
748 + "FROM (SELECT FileId, PathId, FilenameId FROM File WHERE JobId IN (%s)) AS F "
749 + "GROUP BY PathId, FilenameId "
751 + "JOIN Filename ON (Filename.FilenameId = Temp.FilenameId) "
752 + "JOIN Path ON (Path.PathId = Temp.PathId) "
753 + "JOIN File ON (File.FileId = Temp.FileId) "
754 + "WHERE File.FileIndex > 0 ",
757 + return db_sql_query(mdb, buf.c_str(), result_handler, ctx);
761 +/* Full : do nothing
762 + * Differential : get the last full id
763 + * Incremental : get the last full + last diff + last incr(s) ids
765 + * TODO: look and merge from ua_restore.c
767 +bool db_accurate_get_jobids(JCR *jcr, B_DB *mdb,
768 + JOB_DBR *jr, POOLMEM *jobids)
770 + char clientid[50], jobid[50], filesetid[50];
771 + char date[MAX_TIME_LENGTH];
773 + POOL_MEM query (PM_FNAME);
774 + bstrutime(date, sizeof(date), time(NULL) + 1);
778 +"CREATE TEMPORARY TABLE btemp3%s AS ( "
779 + "SELECT JobId, StartTime, EndTime, JobTDate, PurgedFiles "
780 + "FROM Job JOIN FileSet USING (FileSetId) "
781 + "WHERE ClientId = %s "
782 + "AND Level='F' AND JobStatus='T' AND Type='B' "
783 + "AND StartTime<'%s' "
784 + "AND FileSet.FileSet=(SELECT FileSet FROM FileSet WHERE FileSetId = %s) "
785 + "ORDER BY Job.JobTDate DESC LIMIT 1) ",
786 + edit_uint64(jcr->JobId, jobid),
787 + edit_uint64(jr->ClientId, clientid),
789 + edit_uint64(jr->FileSetId, filesetid));
791 + if (!db_sql_query(mdb, query.c_str(), NULL, NULL)) {
795 + if (jr->JobLevel == L_INCREMENTAL) {
798 +"INSERT INTO btemp3%s (JobId, StartTime, EndTime, JobTDate, PurgedFiles) "
799 + "SELECT JobId, StartTime, EndTime, JobTDate, PurgedFiles "
800 + "FROM Job JOIN FileSet USING (FileSetId) "
801 + "WHERE ClientId = %s "
802 + "AND Level='D' AND JobStatus='T' AND Type='B' "
803 + "AND StartTime > (SELECT EndTime FROM btemp3%s ORDER BY EndTime DESC LIMIT 1) "
804 + "AND FileSet.FileSet= (SELECT FileSet FROM FileSet WHERE FileSetId = %s) "
805 + "ORDER BY Job.JobTDate DESC LIMIT 1 ",
811 + db_sql_query(mdb, query.c_str(), NULL, NULL);
814 +"INSERT INTO btemp3%s (JobId, StartTime, EndTime, JobTDate, PurgedFiles) "
815 + "SELECT JobId, StartTime, EndTime, JobTDate, PurgedFiles "
816 + "FROM Job JOIN FileSet USING (FileSetId) "
817 + "WHERE ClientId = %s "
818 + "AND Level='I' AND JobStatus='T' AND Type='B' "
819 + "AND StartTime > (SELECT EndTime FROM btemp3%s ORDER BY EndTime DESC LIMIT 1) "
820 + "AND FileSet.FileSet= (SELECT FileSet FROM FileSet WHERE FileSetId = %s) "
821 + "ORDER BY Job.JobTDate DESC ",
826 + db_sql_query(mdb, query.c_str(), NULL, NULL);
829 + Mmsg(query, "SELECT JobId FROM btemp3%s", jobid);
830 + db_sql_query(mdb, query.c_str(), db_get_int_handler, jobids);
831 + Dmsg1(1, "db_accurate_get_jobids=%s\n", jobids);
833 + Mmsg(query, "DROP TABLE btemp3%s", jobid);
834 + db_sql_query(mdb, query.c_str(), NULL, NULL);
840 + * Use to build a string of int list from a query. "10,20,30"
842 +int db_get_int_handler(void *ctx, int num_fields, char **row)
844 + POOLMEM *ret = (POOLMEM *)ctx;
845 + if (num_fields == 1) {
847 + pm_strcat(ret, ",");
849 + pm_strcat(ret, row[0]);
854 #endif /* HAVE_SQLITE3 || HAVE_MYSQL || HAVE_SQLITE || HAVE_POSTGRESQL*/
855 Index: src/stored/bextract.c
856 ===================================================================
857 --- src/stored/bextract.c (révision 6443)
858 +++ src/stored/bextract.c (copie de travail)
860 Emsg0(M_ERROR_TERM, 0, _("Cannot continue.\n"));
863 + /* handle deleted file
865 + if (rec->FileIndex == 0) {
866 + /* if file is included, remove it ? */
867 + Jmsg(jcr, M_INFO, 0, _("fname=%s is marked as deleted.\n"), attr->fname);
871 if (attr->file_index != rec->FileIndex) {
872 Emsg2(M_ERROR_TERM, 0, _("Record header file index %ld not equal record index %ld\n"),
873 rec->FileIndex, attr->file_index);
874 Index: src/stored/bscan.c
875 ===================================================================
876 --- src/stored/bscan.c (révision 6443)
877 +++ src/stored/bscan.c (copie de travail)
879 case STREAM_UNIX_ATTRIBUTES:
880 case STREAM_UNIX_ATTRIBUTES_EX:
882 + /* handle deleted file
884 + if (rec->FileIndex == 0) {
885 + create_file_attributes_record(db, mjcr, attr->fname, attr->lname,
886 + FT_NOSTAT, "", rec);
891 if (!unpack_attributes_record(bjcr, rec->Stream, rec->data, attr)) {
892 Emsg0(M_ERROR_TERM, 0, _("Cannot continue.\n"));
894 Index: src/stored/append.c
895 ===================================================================
896 --- src/stored/append.c (révision 6443)
897 +++ src/stored/append.c (copie de travail)
900 /* Read Stream header from the File daemon.
901 * The stream header consists of the following:
902 - * file_index (sequential Bacula file index, base 1)
903 + * file_index (sequential Bacula file index, base 1, 0 for deleted files)
904 * stream (Bacula number to distinguish parts of data)
905 * info (Info for Storage daemon -- compressed, encryped, ...)
906 * info is not currently used, so is read, but ignored!
907 @@ -185,16 +185,18 @@
909 Dmsg2(890, "<filed: Header FilInx=%d stream=%d\n", file_index, stream);
911 - if (!(file_index > 0 && (file_index == last_file_index ||
912 - file_index == last_file_index + 1))) {
913 - Jmsg0(jcr, M_FATAL, 0, _("File index from FD not positive or sequential\n"));
916 + if (file_index != 0) { /* TODO: handle file_index == 0 */
917 + if (!(file_index > 0 && (file_index == last_file_index ||
918 + file_index == last_file_index + 1))) {
919 + Jmsg0(jcr, M_FATAL, 0, _("File index from FD not positive or sequential\n"));
923 + if (file_index != last_file_index) {
924 + jcr->JobFiles = file_index;
925 + last_file_index = file_index;
928 - if (file_index != last_file_index) {
929 - jcr->JobFiles = file_index;
930 - last_file_index = file_index;
933 /* Read data stream from the File daemon.
934 * The data stream is just raw bytes
935 @@ -214,22 +216,23 @@
937 while (!write_record_to_block(dcr->block, &rec)) {
938 Dmsg2(850, "!write_record_to_block data_len=%d rem=%d\n", rec.data_len,
941 if (!write_block_to_device(dcr)) {
942 Dmsg2(90, "Got write_block_to_dev error on device %s. %s\n",
943 - dev->print_name(), dev->bstrerror());
944 + dev->print_name(), dev->bstrerror());
950 + Dmsg0(400, "Not OK\n");
953 + jcr->JobBytes += rec.data_len; /* increment bytes this job */
954 + Dmsg4(850, "write_record FI=%s SessId=%d Strm=%s len=%d\n",
955 + FI_to_ascii(buf1, rec.FileIndex), rec.VolSessionId,
956 + stream_to_ascii(buf2, rec.Stream, rec.FileIndex), rec.data_len);
959 - Dmsg0(400, "Not OK\n");
962 - jcr->JobBytes += rec.data_len; /* increment bytes this job */
963 - Dmsg4(850, "write_record FI=%s SessId=%d Strm=%s len=%d\n",
964 - FI_to_ascii(buf1, rec.FileIndex), rec.VolSessionId,
965 - stream_to_ascii(buf2, rec.Stream, rec.FileIndex), rec.data_len);
967 /* Send attributes and digest to Director for Catalog */
968 if (stream == STREAM_UNIX_ATTRIBUTES || stream == STREAM_UNIX_ATTRIBUTES_EX ||
970 ===================================================================
971 --- src/jcr.h (révision 6443)
972 +++ src/jcr.h (copie de travail)
975 /* Forward referenced structures */
982 CRYPTO_CTX crypto; /* Crypto ctx */
983 DIRRES* director; /* Director resource */
984 bool VSS; /* VSS used by FD */
985 + htable *file_list; /* Previous file list (accurate mode) */
986 #endif /* FILE_DAEMON */
989 Index: src/lib/Makefile.in
990 ===================================================================
991 --- src/lib/Makefile.in (révision 6443)
992 +++ src/lib/Makefile.in (copie de travail)
994 res.c rwlock.c scan.c serial.c sha1.c \
995 signal.c smartall.c rblist.c tls.c tree.c \
996 util.c var.c watchdog.c workq.c btimers.c \
997 - address_conf.c pythonlib.c breg.c
998 + address_conf.c pythonlib.c breg.c htable.c
1001 LIBOBJS = attr.o base64.o berrno.o bsys.o bget_msg.o \
1003 res.o rwlock.o scan.o serial.o sha1.o \
1004 signal.o smartall.o rblist.o tls.o tree.o \
1005 util.o var.o watchdog.o workq.o btimers.o \
1006 - address_conf.o pythonlib.o breg.o
1007 + address_conf.o pythonlib.o breg.o htable.o
1010 EXTRAOBJS = @OBJLIST@
1011 Index: src/findlib/find.h
1012 ===================================================================
1013 --- src/findlib/find.h (révision 6443)
1014 +++ src/findlib/find.h (copie de travail)
1016 #define FO_ENHANCEDWILD (1<<23) /* Enhanced wild card processing */
1017 #define FO_CHKCHANGES (1<<24) /* Check if file have been modified during backup */
1018 #define FO_STRIPPATH (1<<25) /* Check for stripping path */
1019 +#define FO_ACCURATE (1<<26) /* Accurate mode */
1021 struct s_included_file {
1022 struct s_included_file *next;