]> git.sur5r.net Git - bacula/bacula/commitdiff
ebl Cleanup
authorEric Bollengier <eric@eb.homelinux.org>
Thu, 13 Mar 2008 14:21:25 +0000 (14:21 +0000)
committerEric Bollengier <eric@eb.homelinux.org>
Thu, 13 Mar 2008 14:21:25 +0000 (14:21 +0000)
git-svn-id: https://bacula.svn.sourceforge.net/svnroot/bacula/trunk@6601 91ce42f0-d328-0410-95d8-f526ca767f89

bacula/patches/testing/clientrunaftervss.patch [deleted file]
bacula/patches/testing/project-accurate-backup-without-lstat.patch [deleted file]
bacula/patches/testing/project-accurate-backup.patch [deleted file]
bacula/patches/testing/project-accurate-backup.patch2 [deleted file]
bacula/patches/testing/project-accurate-backup.sql [deleted file]
bacula/patches/testing/spoolsize_per_job.patch [deleted file]
bacula/patches/testing/spoolsize_per_job.readme [deleted file]
bacula/src/dird/dird_conf.c

diff --git a/bacula/patches/testing/clientrunaftervss.patch b/bacula/patches/testing/clientrunaftervss.patch
deleted file mode 100644 (file)
index 847f76f..0000000
+++ /dev/null
@@ -1,87 +0,0 @@
- Add a new runswhen directive ClientRunAfterVSS 
- "Run After VSS snapshot, but before backup"
-
- It can be applied to Bacula trunk (and probably earlier
- 2.2.x versions) with:
-
- cd <bacula-source>
- ./configure <your options>
- patch -p0 <clientrunaftervss.patch
- make
- ...
- make install
-
-Index: src/dird/dird_conf.c
-===================================================================
---- src/dird/dird_conf.c       (révision 6325)
-+++ src/dird/dird_conf.c       (copie de travail)
-@@ -1688,10 +1688,12 @@
-       *(int *)(item->value) = SCRIPT_Before ;
-    } else if (strcasecmp(lc->str, "after") == 0) {
-       *(int *)(item->value) = SCRIPT_After;
-+   } else if (strcasecmp(lc->str, "aftervss") == 0) {
-+      *(int *)(item->value) = SCRIPT_AfterVSS;
-    } else if (strcasecmp(lc->str, "always") == 0) {
-       *(int *)(item->value) = SCRIPT_Any;
-    } else {
--      scan_err2(lc, _("Expect %s, got: %s"), "Before, After or Always", lc->str);
-+      scan_err2(lc, _("Expect %s, got: %s"), "Before, After, AfterVSS or Always", lc->str);
-    }
-    scan_to_eol(lc);
- }
-Index: src/filed/job.c
-===================================================================
---- src/filed/job.c    (révision 6325)
-+++ src/filed/job.c    (copie de travail)
-@@ -1445,6 +1445,7 @@
-          berrno be;
-          Jmsg(jcr, M_WARNING, 0, _("VSS was not initialized properly. VSS support is disabled. ERR=%s\n"), be.bstrerror());
-       } 
-+      run_scripts(jcr, jcr->RunScripts, "ClientAfterVSS");
-    }
- #endif
-Index: src/lib/runscript.h
-===================================================================
---- src/lib/runscript.h        (révision 6325)
-+++ src/lib/runscript.h        (copie de travail)
-@@ -58,6 +58,7 @@
-    SCRIPT_Never  = 0,
-    SCRIPT_After  = (1<<0),      /* AfterJob */
-    SCRIPT_Before = (1<<1),      /* BeforeJob */
-+   SCRIPT_AfterVSS = (1<<2),  /* BeforeJob and After VSS */
-    SCRIPT_Any    = SCRIPT_Before | SCRIPT_After
- };
-Index: src/lib/runscript.c
-===================================================================
---- src/lib/runscript.c        (révision 6325)
-+++ src/lib/runscript.c        (copie de travail)
-@@ -116,6 +116,8 @@
-    if (strstr(label, NT_("Before"))) {
-       when = SCRIPT_Before;
-+   } else if (bstrcmp(label, NT_("ClientAfterVSS"))) {
-+      when = SCRIPT_AfterVSS;
-    } else {
-       when = SCRIPT_After;
-    }
-@@ -142,6 +144,18 @@
-          }
-       }
-+      if ((script->when & SCRIPT_AfterVSS) && (when & SCRIPT_AfterVSS)) {
-+         if ((script->on_success && (jcr->JobStatus == JS_Blocked))
-+            || (script->on_failure && job_canceled(jcr))
-+            )
-+         {
-+            Dmsg4(200, "runscript: Run it because SCRIPT_AfterVSS (%s,%i,%i,%c)\n", 
-+                  script->command, script->on_success, script->on_failure,
-+                  jcr->JobStatus );
-+            runit = true;
-+         }
-+      }
-+
-       if ((script->when & SCRIPT_After) && (when & SCRIPT_After)) {
-          if ((script->on_success && (jcr->JobStatus == JS_Terminated))
-              || (script->on_failure && job_canceled(jcr))
diff --git a/bacula/patches/testing/project-accurate-backup-without-lstat.patch b/bacula/patches/testing/project-accurate-backup-without-lstat.patch
deleted file mode 100644 (file)
index 667c13c..0000000
+++ /dev/null
@@ -1,184 +0,0 @@
-Index: src/filed/backup.c
-===================================================================
---- src/filed/backup.c (revision 6497)
-+++ src/filed/backup.c (working copy)
-@@ -53,7 +53,8 @@
- typedef struct CurFile {
-    hlink link;
-    char *fname;
--   char *lstat;
-+   time_t ctime;
-+   time_t mtime;
-    bool seen;
- } CurFile;
-@@ -66,24 +67,12 @@
-  * the last time. After we can compare Lstat field. 
-  * 
-  */
--/* TODO: tweak verify code to use the same function ?? */
- bool accurate_check_file(JCR *jcr, FF_PKT *ff_pkt)
- {
--   char *p;
-    int stat=false;
--   struct stat statc;                 /* catalog stat */
--   char *Opts_Digest;
-    char *fname;
-    CurFile *elt;
--   int32_t LinkFIc;
--
--   if (*ff_pkt->VerifyOpts) {   /* use mtime + ctime checks by default */
--      Opts_Digest = ff_pkt->VerifyOpts;
--   } else {
--      Opts_Digest = "cm"; 
--   }
--
-    if (jcr->accurate == false || jcr->JobLevel == L_FULL) {
-       return true;
-    }
-@@ -110,95 +99,14 @@
-       goto bail_out;
-    }
--   decode_stat(elt->lstat, &statc, &LinkFIc); /* decode catalog stat */
--//   *do_Digest = CRYPTO_DIGEST_NONE;
--
--   for (p=Opts_Digest; *p; p++) {
--      char ed1[30], ed2[30];
--      switch (*p) {
--      case 'i':                /* compare INODEs */
--         if (statc.st_ino != ff_pkt->statp.st_ino) {
--            Jmsg(jcr, M_SAVED, 0, _("%s      st_ino   differ. Cat: %s File: %s\n"), fname,
--                 edit_uint64((uint64_t)statc.st_ino, ed1),
--                 edit_uint64((uint64_t)ff_pkt->statp.st_ino, ed2));
--            stat = true;
--         }
--         break;
--      case 'p':                /* permissions bits */
--         if (statc.st_mode != ff_pkt->statp.st_mode) {
--            Jmsg(jcr, M_SAVED, 0, _("%s      st_mode  differ. Cat: %x File: %x\n"), fname,
--                 (uint32_t)statc.st_mode, (uint32_t)ff_pkt->statp.st_mode);
--            stat = true;
--         }
--         break;
--//      case 'n':                /* number of links */
--//         if (statc.st_nlink != ff_pkt->statp.st_nlink) {
--//            Jmsg(jcr, M_SAVED, 0, _("%s      st_nlink differ. Cat: %d File: %d\n"), fname,
--//                 (uint32_t)statc.st_nlink, (uint32_t)ff_pkt->statp.st_nlink);
--//            stat = true;
--//         }
--//         break;
--      case 'u':                /* user id */
--         if (statc.st_uid != ff_pkt->statp.st_uid) {
--            Jmsg(jcr, M_SAVED, 0, _("%s      st_uid   differ. Cat: %u File: %u\n"), fname,
--                 (uint32_t)statc.st_uid, (uint32_t)ff_pkt->statp.st_uid);
--            stat = true;
--         }
--         break;
--      case 'g':                /* group id */
--         if (statc.st_gid != ff_pkt->statp.st_gid) {
--            Jmsg(jcr, M_SAVED, 0, _("%s      st_gid   differ. Cat: %u File: %u\n"), fname,
--                 (uint32_t)statc.st_gid, (uint32_t)ff_pkt->statp.st_gid);
--            stat = true;
--         }
--         break;
--      case 's':                /* size */
--         if (statc.st_size != ff_pkt->statp.st_size) {
--            Jmsg(jcr, M_SAVED, 0, _("%s      st_size  differ. Cat: %s File: %s\n"), fname,
--                 edit_uint64((uint64_t)statc.st_size, ed1),
--                 edit_uint64((uint64_t)ff_pkt->statp.st_size, ed2));
--            stat = true;
--         }
--         break;
--//      case 'a':                /* access time */
--//         if (statc.st_atime != ff_pkt->statp.st_atime) {
--//            Jmsg(jcr, M_SAVED, 0, _("%s      st_atime differs\n"), fname);
--//            stat = true;
--//         }
--//         break;
--      case 'm':
--         if (statc.st_mtime != ff_pkt->statp.st_mtime) {
--            Jmsg(jcr, M_SAVED, 0, _("%s      st_mtime differs\n"), fname);
--            stat = true;
--         }
--         break;
--      case 'c':                /* ctime */
--         if (statc.st_ctime != ff_pkt->statp.st_ctime) {
--            Jmsg(jcr, M_SAVED, 0, _("%s      st_ctime differs\n"), fname);
--            stat = true;
--         }
--         break;
--      case 'd':                /* file size decrease */
--         if (statc.st_size > ff_pkt->statp.st_size) {
--            Jmsg(jcr, M_SAVED, 0, _("%s      st_size  decrease. Cat: %s File: %s\n"), fname,
--                 edit_uint64((uint64_t)statc.st_size, ed1),
--                 edit_uint64((uint64_t)ff_pkt->statp.st_size, ed2));
--            stat = true;
--         }
--         break;
--      case '5':                /* compare MD5 */
--         Dmsg1(500, "set Do_MD5 for %s\n", ff_pkt->fname);
--//       *do_Digest = CRYPTO_DIGEST_MD5;
--         break;
--      case '1':                 /* compare SHA1 */
--//       *do_Digest = CRYPTO_DIGEST_SHA1;
--         break;
--      case ':':
--      case 'V':
--      default:
--         break;
--      }
-+   if (elt->mtime != ff_pkt->statp.st_mtime) {
-+     Jmsg(jcr, M_SAVED, 0, _("%s      st_mtime differs\n"), fname);
-+     stat = true;
-+   } else if (elt->ctime != ff_pkt->statp.st_ctime) {
-+     Jmsg(jcr, M_SAVED, 0, _("%s      st_ctime differs\n"), fname);
-+     stat = true;
-    }
-+
-    accurate_mark_file_as_seen(elt);
-    Dmsg2(500, "accurate %s = %i\n", fname, stat);
-@@ -215,8 +123,11 @@
- {
-    BSOCK *dir = jcr->dir_bsock;
-    int len;
-+   struct stat statp;
-+   int32_t LinkFIc;
-    uint64_t nb;
-    CurFile *elt=NULL;
-+   char *lstat;
-    if (jcr->accurate==false || job_canceled(jcr) || jcr->JobLevel==L_FULL) {
-       return true;
-@@ -246,10 +157,13 @@
-          elt->fname  = (char *) elt+sizeof(CurFile);
-          memcpy(elt->fname, dir->msg, dir->msglen);
-          elt->fname[dir->msglen]='\0';
--         elt->lstat = elt->fname + len + 1;
--         elt->seen=0;
-+         lstat = elt->fname + len + 1;
-+         decode_stat(lstat, &statp, &LinkFIc); /* decode catalog stat */
-+         elt->ctime = statp.st_ctime;
-+         elt->mtime = statp.st_mtime;
-+         elt->seen = 0;
-          jcr->file_list->insert(elt->fname, elt); 
--         Dmsg2(500, "add fname=%s lstat=%s\n", elt->fname, elt->lstat);
-+         Dmsg2(500, "add fname=%s lstat=%s\n", elt->fname, lstat);
-       }
-    }
-@@ -280,9 +194,10 @@
-    foreach_htable (elt, jcr->file_list) {
-       if (!accurate_file_has_been_seen(elt)) { /* already seen */
--         Dmsg3(500, "deleted fname=%s lstat=%s seen=%i\n", elt->fname, elt->lstat, elt->seen);
-+         Dmsg2(500, "deleted fname=%s seen=%i\n", elt->fname, elt->seen);
-          ff_pkt->fname = elt->fname;
--         decode_stat(elt->lstat, &ff_pkt->statp, &ff_pkt->LinkFI); /* decode catalog stat */
-+         ff_pkt->statp.st_mtime = elt->mtime;
-+         ff_pkt->statp.st_ctime = elt->ctime;
-          encode_and_send_attributes(jcr, ff_pkt, stream);
-       }
- //      Free(elt->fname);
diff --git a/bacula/patches/testing/project-accurate-backup.patch b/bacula/patches/testing/project-accurate-backup.patch
deleted file mode 100644 (file)
index 4ec8610..0000000
+++ /dev/null
@@ -1,1615 +0,0 @@
-Index: src/dird/fd_cmds.c
-===================================================================
---- src/dird/fd_cmds.c (révision 6372)
-+++ src/dird/fd_cmds.c (copie de travail)
-@@ -50,7 +50,7 @@
- static char filesetcmd[]  = "fileset%s\n"; /* set full fileset */
- static char jobcmd[]      = "JobId=%s Job=%s SDid=%u SDtime=%u Authorization=%s\n";
- /* Note, mtime_only is not used here -- implemented as file option */
--static char levelcmd[]    = "level = %s%s mtime_only=%d\n";
-+static char levelcmd[]    = "level = %s%s%s mtime_only=%d\n";
- static char runscript[]   = "Run OnSuccess=%u OnFailure=%u AbortOnError=%u When=%u Command=%s\n";
- static char runbeforenow[]= "RunBeforeNow\n";
-@@ -189,6 +189,12 @@
-          bsnprintf(since, since_len, _(" (upgraded from %s)"),
-             level_to_str(jcr->JobLevel));
-          jcr->JobLevel = jcr->jr.JobLevel = L_FULL;
-+      /* look if we found the last accurate backup */
-+      } else if (jcr->accurate && !db_accurate_find_backupid(jcr, jcr->db, &jcr->jr)) {
-+         Jmsg(jcr, M_INFO, 0, _("No prior or suitable Full accurate backup found in catalog. Doing FULL backup.\n"));
-+         bsnprintf(since, since_len, _(" (upgraded from %s)"),
-+                 level_to_str(jcr->JobLevel));
-+         jcr->JobLevel = jcr->jr.JobLevel = L_FULL;
-       } else {
-          if (jcr->job->rerun_failed_levels) {
-             if (db_find_failed_job_since(jcr, jcr->db, &jcr->jr, jcr->stime, JobLevel)) {
-@@ -217,7 +223,7 @@
-    char ed1[50];
-    stime = str_to_utime(jcr->stime);
--   fd->fsend(levelcmd, NT_("since_utime "), edit_uint64(stime, ed1), 0);
-+   fd->fsend(levelcmd, "", NT_("since_utime "), edit_uint64(stime, ed1), 0);
-    while (bget_dirmsg(fd) >= 0) {  /* allow him to poll us to sync clocks */
-       Jmsg(jcr, M_INFO, 0, "%s\n", fd->msg);
-    }
-@@ -231,24 +237,25 @@
- bool send_level_command(JCR *jcr)
- {
-    BSOCK   *fd = jcr->file_bsock;
-+   const char *accurate=jcr->job->accurate?"accurate_":"";
-    /*
-     * Send Level command to File daemon
-     */
-    switch (jcr->JobLevel) {
-    case L_BASE:
--      fd->fsend(levelcmd, "base", " ", 0);
-+      fd->fsend(levelcmd, "", "base", " ", 0);
-       break;
-    /* L_NONE is the console, sending something off to the FD */
-    case L_NONE:
-    case L_FULL:
--      fd->fsend(levelcmd, "full", " ", 0);
-+      fd->fsend(levelcmd, "", "full", " ", 0);
-       break;
-    case L_DIFFERENTIAL:
--      fd->fsend(levelcmd, "differential", " ", 0);
-+      fd->fsend(levelcmd, accurate, "differential", " ", 0);
-       send_since_time(jcr);
-       break;
-    case L_INCREMENTAL:
--      fd->fsend(levelcmd, "incremental", " ", 0);
-+      fd->fsend(levelcmd, accurate, "incremental", " ", 0);
-       send_since_time(jcr);
-       break;
-    case L_SINCE:
-Index: src/dird/backup.c
-===================================================================
---- src/dird/backup.c  (révision 6372)
-+++ src/dird/backup.c  (copie de travail)
-@@ -44,6 +44,7 @@
- #include "bacula.h"
- #include "dird.h"
- #include "ua.h"
-+#include "findlib/find.h"
- /* Commands sent to File daemon */
- static char backupcmd[] = "backup\n";
-@@ -96,7 +97,450 @@
-    return true;
- }
-+static int accurate_list_handler(void *ctx, int num_fields, char **row)
-+{
-+   JCR *jcr = (JCR *)ctx;
-+
-+   if (job_canceled(jcr)) {
-+      return 1;
-+   }
-+   
-+   if (row[0] > 0) {
-+      jcr->file_bsock->fsend("%s%s%c%s", row[1], row[2], 0, row[3]); 
-+   }
-+   return 0;
-+}
-+
-+bool db_get_jobids(JCR *jcr)
-+{
-+   
-+}
-+
-+bool accurate_send_current_files(JCR *jcr)
-+{
-+   char buf[MAXSTRING];
-+   char ed1[50], ed2[50];
- /*
-+ CREATE TEMPORARY TABLE btemp2 AS (
-+  SELECT max(FileId) as FileId, PathId, FilenameId 
-+    FROM (SELECT FileId, PathId, FilenameId FROM File WHERE JobId IN (39867,40341)) AS F
-+   GROUP BY PathId, FilenameId )
-+
-+  SELECT File.FileIndex, Path.Path, Filename.Name, File.LStat
-+    FROM btemp2 JOIN Path USING (PathId) JOIN Filename USING (FilenameId)
-+                JOIN File USING (FileId)
-+   WHERE File.FileIndex > 0
-+
-+ DROP TABLE btemp2
-+
-+SELECT DISTINCT ON (PathId, FilenameId) FileIndex, Path, Name, LStat
-+  FROM File JOIN Filename USING (FilenameId) JOIN Path USING (PathId) WHERE JobId IN (40341)
-+ ORDER BY PathId, FilenameId, JobId DESC
-+*/
-+   bsnprintf(buf, sizeof(buf),
-+           "SELECT DISTINCT ON (PathId, FilenameId) FileIndex, Path, Name, LStat "
-+            "FROM File JOIN Filename USING (FilenameId) JOIN Path USING (PathId) WHERE JobId IN (%s)"
-+              "ORDER BY PathId, FilenameId, JobId DESC",
-+           "10,20,30");       /* jobid */
-+
-+   Dmsg1(2, "display current files cmd=%s\n", buf);
-+   db_sql_query(jcr->db, buf, accurate_list_handler, (void *)jcr);
-+   jcr->file_bsock->signal(BNET_EOD);
-+   return true;
-+}
-+
-+/*
-+ * We are called here for each record that matches the above
-+ *  SQL query -- that is for each file contained in the Catalog
-+ *  that was not marked earlier. This means that the file in
-+ *  question is a missing file (in the Catalog but not on Disk).
-+ */
-+/* TODO: tweak verify code to use the same function */
-+bool accurate_check_file(JCR *jcr, FILE_DBR *fdbr, char *attr, char *Opts_Digest, int *do_Digest)
-+{
-+   char *p;
-+   int stat=false;
-+   struct stat statf;                 /* file stat */
-+   struct stat statc;                 /* catalog stat */
-+
-+   int32_t LinkFIf, LinkFIc;
-+
-+   decode_stat(attr, &statf, &LinkFIf);  /* decode file stat packet */
-+   decode_stat(fdbr->LStat, &statc, &LinkFIc); /* decode catalog stat */
-+   *do_Digest = CRYPTO_DIGEST_NONE;
-+
-+   for (p=Opts_Digest; *p; p++) {
-+      char ed1[30], ed2[30];
-+      switch (*p) {
-+      case 'i':                /* compare INODEs */
-+       if (statc.st_ino != statf.st_ino) {
-+          Jmsg(jcr, M_INFO, 0, _("      st_ino   differ. Cat: %s File: %s\n"),
-+               edit_uint64((uint64_t)statc.st_ino, ed1),
-+               edit_uint64((uint64_t)statf.st_ino, ed2));
-+          stat = true;
-+       }
-+       break;
-+      case 'p':                /* permissions bits */
-+       if (statc.st_mode != statf.st_mode) {
-+          Jmsg(jcr, M_INFO, 0, _("      st_mode  differ. Cat: %x File: %x\n"),
-+               (uint32_t)statc.st_mode, (uint32_t)statf.st_mode);
-+          stat = true;
-+       }
-+       break;
-+      case 'n':                /* number of links */
-+       if (statc.st_nlink != statf.st_nlink) {
-+          Jmsg(jcr, M_INFO, 0, _("      st_nlink differ. Cat: %d File: %d\n"),
-+               (uint32_t)statc.st_nlink, (uint32_t)statf.st_nlink);
-+          stat = true;
-+       }
-+       break;
-+      case 'u':                /* user id */
-+       if (statc.st_uid != statf.st_uid) {
-+          Jmsg(jcr, M_INFO, 0, _("      st_uid   differ. Cat: %u File: %u\n"),
-+               (uint32_t)statc.st_uid, (uint32_t)statf.st_uid);
-+          stat = true;
-+       }
-+       break;
-+      case 'g':                /* group id */
-+       if (statc.st_gid != statf.st_gid) {
-+          Jmsg(jcr, M_INFO, 0, _("      st_gid   differ. Cat: %u File: %u\n"),
-+               (uint32_t)statc.st_gid, (uint32_t)statf.st_gid);
-+          stat = true;
-+       }
-+       break;
-+      case 's':                /* size */
-+       if (statc.st_size != statf.st_size) {
-+          Jmsg(jcr, M_INFO, 0, _("      st_size  differ. Cat: %s File: %s\n"),
-+               edit_uint64((uint64_t)statc.st_size, ed1),
-+               edit_uint64((uint64_t)statf.st_size, ed2));
-+          stat = true;
-+       }
-+       break;
-+      case 'a':                /* access time */
-+       if (statc.st_atime != statf.st_atime) {
-+          Jmsg(jcr, M_INFO, 0, _("      st_atime differs\n"));
-+          stat = true;
-+       }
-+       break;
-+      case 'm':
-+       if (statc.st_mtime != statf.st_mtime) {
-+          Jmsg(jcr, M_INFO, 0, _("      st_mtime differs\n"));
-+          stat = true;
-+       }
-+       break;
-+      case 'c':                /* ctime */
-+       if (statc.st_ctime != statf.st_ctime) {
-+          Jmsg(jcr, M_INFO, 0, _("      st_ctime differs\n"));
-+          stat = true;
-+       }
-+       break;
-+      case 'd':                /* file size decrease */
-+       if (statc.st_size > statf.st_size) {
-+          Jmsg(jcr, M_INFO, 0, _("      st_size  decrease. Cat: %s File: %s\n"),
-+               edit_uint64((uint64_t)statc.st_size, ed1),
-+               edit_uint64((uint64_t)statf.st_size, ed2));
-+          stat = true;
-+       }
-+       break;
-+      case '5':                /* compare MD5 */
-+       Dmsg1(500, "set Do_MD5 for %s\n", jcr->fname);
-+       *do_Digest = CRYPTO_DIGEST_MD5;
-+       break;
-+      case '1':                 /* compare SHA1 */
-+       *do_Digest = CRYPTO_DIGEST_SHA1;
-+       break;
-+      case ':':
-+      case 'V':
-+      default:
-+       break;
-+      }
-+   }
-+   return stat;
-+}
-+
-+/*
-+ * This function is called at EOJ.
-+ *  For a Full backup, we remove old one, and we add all entries 
-+ *  For an Incremental, we add all entries (delete have been before)
-+ *  For a Differential, we add all entries (delete have been before)
-+ * 
-+ * TODO: 
-+ *      
-+ */
-+bool accurate_update_current_files(JCR *jcr)
-+{
-+   JobId_t backupid;
-+
-+   if (jcr->accurate == false) {
-+      return true;
-+   }
-+
-+   backupid = db_accurate_find_backupid(jcr, jcr->db, &jcr->jr);
-+
-+   Dmsg1(1, "backupid = %i\n", backupid);
-+
-+   if (!backupid) {
-+      return false;           /* something goes wrong */
-+   }
-+
-+   if (jcr->JobLevel == L_FULL) {
-+      db_accurate_cleanup_currentfile(jcr, jcr->db, backupid);
-+   }
-+
-+   db_accurate_update_currentfile(jcr, jcr->db, jcr->JobId, 
-+                                jcr->JobLevel, backupid);
-+   return true;
-+}
-+
-+/*
-+ * We are called here for each record that matches the above
-+ *  SQL query -- that is for each file contained in the Catalog
-+ *  that was not marked earlier. This means that the file in
-+ *  question is a missing file (in the Catalog but not on Disk).
-+ */
-+static int accurate_handler(void *ctx, int num_fields, char **row)
-+{
-+   JCR *jcr = (JCR *)ctx;
-+
-+   if (job_canceled(jcr)) {
-+      return 1;
-+   }
-+   if (num_fields == 2) {     /* deleted files */
-+      jcr->file_bsock->fsend("%s%s", row[0]?row[0]:"", row[1]?row[1]:""); 
-+   } else if (num_fields == 1) { /* files to backup */
-+      jcr->file_bsock->fsend("%s", row[0]?row[0]:""); 
-+   }
-+   return 0;
-+}
-+
-+/*
-+ * Send deleted files and files to backup in accurate mode
-+ *
-+ */
-+static int accurate_send_missing_and_deleted_files(JCR *jcr, JobId_t BackupId)
-+{
-+   char buf[MAXSTRING];
-+   char ed1[50], ed2[50];
-+
-+   bsnprintf(buf, sizeof(buf),
-+           "SELECT Name FROM ToBackup%s",
-+           edit_uint64(jcr->JobId, ed2));
-+
-+   /* missing_handler is called for each file found */
-+   Dmsg1(2, "display files to backup cmd=%s\n", buf);
-+   db_sql_query(jcr->db, buf, accurate_handler, (void *)jcr);
-+   jcr->file_bsock->signal(BNET_EOD);
-+
-+   bsnprintf(buf, sizeof(buf),
-+      "SELECT Path.Path,Filename.Name "
-+        "FROM CurrentFile "
-+             "JOIN File USING (FileId) "
-+             "JOIN Path USING (PathId) "
-+             "JOIN Filename USING (FilenameId) "
-+      "WHERE CurrentFile.BackupId=%s "
-+        "AND CurrentFile.MarkId!=%s ",
-+           edit_uint64(BackupId, ed1), edit_uint64(jcr->JobId, ed2));
-+   /* missing_handler is called for each file found */
-+   Dmsg1(2, "display deleted files cmd=%s\n", buf);
-+   db_sql_query(jcr->db, buf, accurate_handler, (void *)jcr);
-+   jcr->file_bsock->signal(BNET_EOD);
-+   
-+   return 1;
-+}
-+
-+/*
-+ * Accurate backup mode
-+ * 1. Receive the list of all files including those backed up to the Dir
-+ * 2. Dir computes files and deleted files.
-+ * 3. Dir sends list of additional files (new files) to backup,
-+ *    and list of files deleted.
-+ *
-+ * Cleanup attributes (don't use atime, inode etc..)
-+ * Need to insert file and attributes to temp table ?
-+ * Batch compare files and attributes ?
-+ *
-+ * If file have file_index=0, they are discarded by FD
-+ *
-+ * TODO: send deleted list and new list to client
-+ *       tweak SD with file_index=-1
-+ */
-+bool accurate_compute_files(JCR *jcr)
-+{
-+   BSOCK   *fd;
-+   char buf[MAXSTRING];
-+   int n, len;
-+   FILE_DBR fdbr;
-+   POOLMEM *fname = get_pool_memory(PM_MESSAGE);
-+   int do_Digest = CRYPTO_DIGEST_NONE;
-+   int32_t file_index = 0;
-+   JobId_t JobId=0;           /* TODO: compute the job key in new table */
-+   JobId_t backupid=0;
-+
-+   memset(&fdbr, 0, sizeof(FILE_DBR));
-+   fd = jcr->file_bsock;
-+   fdbr.JobId = JobId;                
-+   jcr->FileIndex = 0;
-+
-+   if (jcr->accurate == false || jcr->JobLevel == L_FULL) {
-+      return true;
-+   }
-+
-+   backupid = db_accurate_find_backupid(jcr, jcr->db, &jcr->jr);
-+   if (!backupid) {
-+      Jmsg(jcr, M_FATAL, 0, _("Can't use Accurate mode ERR=Can't find BackupId\n"));
-+      return false;
-+   }
-+   db_accurate_create_tobackup_table(jcr, jcr->db, jcr->JobId);
-+   Dmsg0(1, "bdird: waiting to receive file attributes\n");
-+   /*
-+    * Get Attributes and Signature from File daemon
-+    * We expect:
-+    *   FileIndex
-+    *   Stream
-+    *   Options or Digest (MD5/SHA1)
-+    *   Filename
-+    *   Attributes
-+    *   Link name  ???
-+    */
-+   while ((n=bget_dirmsg(fd)) >= 0 && !job_canceled(jcr)) {
-+      int stream;
-+      char *attr, *p, *fn;
-+      char Opts_Digest[MAXSTRING];        /* Verify Opts or MD5/SHA1 digest */
-+
-+      if (job_canceled(jcr)) {
-+         goto bail_out2;
-+      }
-+      fname = check_pool_memory_size(fname, fd->msglen);
-+      jcr->fname = check_pool_memory_size(jcr->fname, fd->msglen);
-+      Dmsg1(1, "Atts+Digest=%s\n", fd->msg);
-+      if ((len = sscanf(fd->msg, "%ld %d %100s", &file_index, &stream,
-+            fname)) != 3) {
-+         Jmsg3(jcr, M_FATAL, 0, _("bird<filed: bad attributes, expected 3 fields got %d\n"
-+" mslen=%d msg=%s\n"), len, fd->msglen, fd->msg);
-+         goto bail_out2;
-+      }
-+      /*
-+       * We read the Options or Signature into fname
-+       *  to prevent overrun, now copy it to proper location.
-+       */
-+      bstrncpy(Opts_Digest, fname, sizeof(Opts_Digest));
-+      p = fd->msg;
-+      skip_nonspaces(&p);             /* skip FileIndex */
-+      skip_spaces(&p);
-+      skip_nonspaces(&p);             /* skip Stream */
-+      skip_spaces(&p);
-+      skip_nonspaces(&p);             /* skip Opts_Digest */
-+      p++;                            /* skip space */
-+      fn = fname;
-+      while (*p != 0) {
-+         *fn++ = *p++;                /* copy filename */
-+      }
-+      *fn = *p++;                     /* term filename and point to attribs */
-+      attr = p;
-+      /*
-+       * Got attributes stream, decode it
-+       */
-+      if (stream == STREAM_UNIX_ATTRIBUTES || stream == STREAM_UNIX_ATTRIBUTES_EX) {
-+       int changed=true;
-+         Dmsg2(400, "file_index=%d attr=%s\n", file_index, attr);
-+         jcr->JobFiles++;
-+         jcr->FileIndex = file_index;    /* remember attribute file_index */
-+         do_Digest = CRYPTO_DIGEST_NONE;
-+         pm_strcpy(jcr->fname, fname);  /* move filename into JCR */
-+       fdbr.FileId = 0;
-+
-+         /*
-+          * Find equivalent record in the database
-+          */
-+       
-+       if (db_accurate_get_file_attributes_record(jcr, jcr->db, jcr->fname,
-+                                                  backupid, &fdbr))
-+       {
-+          Dmsg2(1, "get_file ok fname=%s fileid=%i\n", jcr->fname, fdbr.FileId);
-+          if (fdbr.MarkId != jcr->JobId) {           /* Already visited ? */
-+             if (file_index == 0) { /* file not saved */
-+                changed = accurate_check_file(jcr, &fdbr, attr, Opts_Digest, &do_Digest);
-+                Dmsg1(1, "check_file changed=%i\n", changed);
-+                
-+                if (changed == true) {
-+                   db_accurate_mark_file_for_backup(jcr, jcr->db, jcr->fname, jcr->JobId);
-+                   db_accurate_delete_file_record(jcr, jcr->db, fdbr.FileId, backupid);
-+                } else {
-+                   db_accurate_mark_file_record(jcr, jcr->db, backupid,
-+                                                fdbr.FileId, jcr->JobId);
-+                }
-+             } else {         /* file_index != 0 file have be backuped */
-+                db_accurate_delete_file_record(jcr, jcr->db, fdbr.FileId, backupid);
-+             }
-+          } else {
-+             Dmsg2(1, "already saved fname=%s fileid=%i\n", jcr->fname, fdbr.FileId);
-+          }
-+       } else if (file_index == 0) {
-+             Dmsg1(1, "mark_for_backup fname=%s\n", jcr->fname);
-+             db_accurate_mark_file_for_backup(jcr, jcr->db, jcr->fname, jcr->JobId);
-+       }
-+      
-+      /*
-+       * Got Digest Signature from Storage daemon
-+       *  It came across in the Opts_Digest field.
-+       */
-+       /* not used */
-+      } else if (crypto_digest_stream_type(stream) != CRYPTO_DIGEST_NONE) {
-+         Dmsg2(400, "stream=Digest inx=%d Digest=%s\n", file_index, Opts_Digest);
-+         /*
-+          * When ever we get a digest it MUST have been
-+          * preceded by an attributes record, which sets attr_file_index
-+          */
-+         if (jcr->FileIndex != (uint32_t)file_index) {
-+            Jmsg2(jcr, M_FATAL, 0, _("MD5/SHA1 index %d not same as attributes %d\n"),
-+               file_index, jcr->FileIndex);
-+            goto bail_out2;
-+         }
-+         if (do_Digest != CRYPTO_DIGEST_NONE) {
-+            db_escape_string(jcr, jcr->db, buf, Opts_Digest, strlen(Opts_Digest));
-+            if (strcmp(buf, fdbr.Digest) != 0) {
-+               if (debug_level >= 10) {
-+                  Jmsg(jcr, M_INFO, 0, _("      %d not same. File=%s Cat=%s\n"),
-+                       stream, buf, fdbr.Digest);
-+               } else {
-+                  Jmsg(jcr, M_INFO, 0, _("      %d differs.\n"),
-+                       stream);
-+               }
-+               //stat = JS_Differences;
-+            }
-+            do_Digest = CRYPTO_DIGEST_NONE;
-+         }
-+      }
-+//      jcr->JobFiles = file_index;
-+   }
-+   if (is_bnet_error(fd)) {
-+      berrno be;
-+      Jmsg2(jcr, M_FATAL, 0, _("bdird<filed: bad attributes from filed n=%d : %s\n"),
-+                        n, be.bstrerror());
-+      goto bail_out2;
-+   }
-+
-+/*
-+CREATE  VIEW cf AS SELECT path.path || filename.name as filename, 
-+       jobid, currentfile.markid, backupid 
-+  FROM File join currentfile using (fileid) join filename using (filenameid) join path using (pathid)
-+*/
-+
-+   accurate_send_missing_and_deleted_files(jcr, backupid);
-+
-+   db_accurate_clean_deleted_files(jcr, jcr->db, jcr->JobId, backupid);
-+
-+   db_accurate_drop_tobackup_table(jcr, jcr->db, jcr->JobId);
-+
-+   free_pool_memory(fname);
-+   return true;
-+
-+bail_out2:
-+   db_accurate_drop_tobackup_table(jcr, jcr->db, jcr->JobId);
-+   return false;
-+}
-+
-+/*
-  * Do a backup of the specified FileSet
-  *
-  *  Returns:  false on failure
-@@ -231,9 +675,18 @@
-       goto bail_out;
-    }
-+   /*
-+    * If backup is in accurate mode, FD will send the list of
-+    * all files. We have to store it, and compute witch files
-+    * have been deleted and witch files have to be backuped.
-+    */
-+   accurate_compute_files(jcr);
-+
-    /* Pickup Job termination data */
-    stat = wait_for_job_termination(jcr);
-    db_write_batch_file_records(jcr);    /* used by bulk batch file insert */
-+   accurate_update_current_files(jcr);
-+
-    if (stat == JS_Terminated) {
-       backup_cleanup(jcr, stat);
-       return true;
-Index: src/dird/inc_conf.c
-===================================================================
---- src/dird/inc_conf.c        (révision 6372)
-+++ src/dird/inc_conf.c        (copie de travail)
-@@ -94,6 +94,7 @@
-  * Items that are valid in an Options resource
-  */
- static RES_ITEM options_items[] = {
-+   {"accurate",        store_opts,    {0},     0, 0, 0},
-    {"compression",     store_opts,    {0},     0, 0, 0},
-    {"signature",       store_opts,    {0},     0, 0, 0},
-    {"verify",          store_opts,    {0},     0, 0, 0},
-@@ -153,7 +154,8 @@
-    INC_KW_NOATIME,
-    INC_KW_ENHANCEDWILD,
-    INC_KW_CHKCHANGES,
--   INC_KW_STRIPPATH
-+   INC_KW_STRIPPATH,
-+   INC_KW_ACCURATE
- };
- /*
-@@ -163,6 +165,7 @@
-  *   options given above.
-  */
- static struct s_kw FS_option_kw[] = {
-+   {"accurate",    INC_KW_ACCURATE},
-    {"compression", INC_KW_COMPRESSION},
-    {"signature",   INC_KW_DIGEST},
-    {"encryption",  INC_KW_ENCRYPTION},
-@@ -251,6 +254,8 @@
-    {"no",       INC_KW_ENHANCEDWILD,  "0"},
-    {"yes",      INC_KW_CHKCHANGES,    "c"},
-    {"no",       INC_KW_CHKCHANGES,    "0"},
-+   {"yes",      INC_KW_ACCURATE,      "C"},
-+   {"no",       INC_KW_ACCURATE,      "0"},
-    {NULL,       0,                      0}
- };
-Index: src/filed/backup.c
-===================================================================
---- src/filed/backup.c (révision 6372)
-+++ src/filed/backup.c (copie de travail)
-@@ -48,8 +48,114 @@
- static bool crypto_session_start(JCR *jcr);
- static void crypto_session_end(JCR *jcr);
- static bool crypto_session_send(JCR *jcr, BSOCK *sd);
-+static bool encode_and_send_deleted_file(JCR *jcr, char *fname);
- /*
-+ * Called by save_file when accept/discard file for backup
-+ *
-+ * TODO: we could add MD5/SHAX digest, but we have to compute it
-+ * for all files.
-+ */
-+static bool accurate_add_file(JCR *jcr, FF_PKT *ff_pkt, char *stats)
-+{
-+   char *a=stats;
-+   char attribs[MAXSTRING];
-+   uint32_t file_index=jcr->JobFiles;
-+   BSOCK *dir = jcr->dir_bsock;
-+   int stat;
-+
-+   if (jcr->accurate == false || jcr->JobLevel == L_FULL) {
-+      return true;
-+   }
-+
-+   if (!stats) {              /* TODO: don't always compute attribute  */
-+      file_index=0;
-+      encode_stat(attribs, ff_pkt, 0);
-+      a = attribs;
-+   }
-+
-+   switch (ff_pkt->type) {
-+   case FT_LNKSAVED:                  /* Hard linked, file already saved */
-+   case FT_LNK:
-+      stat = dir->fsend("%d %d %s %s%c%s%c%s%c", file_index,
-+            STREAM_UNIX_ATTRIBUTES, ff_pkt->VerifyOpts, ff_pkt->fname,
-+            0, a, 0, ff_pkt->link, 0);
-+      break;
-+   case FT_REGE:
-+   case FT_REG:
-+   case FT_SPEC:
-+   case FT_RAW:
-+   case FT_FIFO:
-+   case FT_NOCHG:
-+      stat = dir->fsend("%d %d %s %s%c%s%c%c", file_index,
-+            STREAM_UNIX_ATTRIBUTES, ff_pkt->VerifyOpts, ff_pkt->fname,
-+            0, a, 0, 0);
-+
-+      break;
-+   case FT_REPARSE: 
-+   case FT_DIREND:
-+   case FT_NORECURSE:
-+   case FT_DIRNOCHG:
-+      stat = dir->fsend("%d %d %s %s%c%s%c%c", file_index,
-+               STREAM_UNIX_ATTRIBUTES, ff_pkt->VerifyOpts, ff_pkt->link,
-+               0, a, 0, 0);
-+      break;
-+   default:
-+      Dmsg2(1, _("Fname=%s Type=%i\n"), ff_pkt->fname, ff_pkt->type);
-+      return true;
-+   }
-+
-+   if (!stat) {
-+      Jmsg(jcr, M_FATAL, 0, _("Network error in send to Director: ERR=%s\n"), bnet_strerror(dir));
-+      return 0;
-+   }
-+
-+   return true;
-+}
-+
-+/* build a fileset with new files from director */
-+static bool accurate_get_new_and_deleted_file_list(JCR *jcr)
-+{   
-+   BSOCK *dir = jcr->dir_bsock;
-+   if (jcr->accurate == false || job_canceled(jcr)) {
-+      return true;
-+   }
-+
-+   /* get missing files */
-+   while (dir->recv() >= 0) {
-+      Dmsg1(1, "missing = %s\n", dir->msg);
-+   }
-+
-+   /* get deleted files */
-+   while (dir->recv() >= 0) {
-+      Dmsg1(1, "deleted = %s\n", dir->msg);
-+      encode_and_send_deleted_file(jcr, dir->msg); 
-+   }
-+  
-+   return true;
-+}
-+
-+/* send deleted file list to stored */
-+static bool accurate_send_deleted_list(JCR *jcr)
-+{
-+   if (jcr->accurate == false || job_canceled(jcr)) {
-+      return true;
-+   }
-+   return true;
-+}
-+
-+static bool accurate_send_file_list(JCR *jcr)
-+{
-+   if (jcr->accurate == false || job_canceled(jcr)) {
-+      return true;
-+   }
-+   Dmsg0(1, "Sending BNET_EOD\n");
-+   jcr->dir_bsock->signal(BNET_EOD);            /* end of sending data */
-+   return true;
-+}
-+
-+
-+/*
-  * Find all the requested files and send them
-  * to the Storage daemon.
-  *
-@@ -66,7 +172,6 @@
-    BSOCK *sd;
-    bool ok = true;
-    // TODO landonf: Allow user to specify encryption algorithm
--
-    sd = jcr->store_bsock;
-    set_jcr_job_status(jcr, JS_Running);
-@@ -134,6 +239,20 @@
-       ok = false;                     /* error */
-       set_jcr_job_status(jcr, JS_ErrorTerminated);
-    }
-+   Dmsg1(1, "jcr->accurate == %i\n", jcr->accurate);
-+   /* start accurate stuffs */
-+   if (jcr->accurate) {
-+      /* TODO: test job_canceled() */
-+      accurate_send_file_list(jcr);                 /* send all files to DIR */
-+      accurate_get_new_and_deleted_file_list(jcr);  /* get a new incr fileset from DIR */
-+//      set_find_options((FF_PKT *)jcr->ff, 0, 0);            /* we backup all that director wants */
-+//      if (!find_files(jcr, (FF_PKT *)jcr->ff, save_file)) {
-+//     ok = false;                     /* error */
-+//     set_jcr_job_status(jcr, JS_ErrorTerminated);
-+//      }
-+//      accurate_send_file_list(jcr);                 /* send all new files to DIR */
-+      accurate_send_deleted_list(jcr);              /* send deleted list to SD  */
-+   }
-    free_pool_memory(jcr->acl_text);
-@@ -355,9 +474,11 @@
-    case FT_DIRNOCHG:
-    case FT_NOCHG:
-       Jmsg(jcr, M_SKIPPED, 1, _("     Unchanged file skipped: %s\n"), ff_pkt->fname);
-+      accurate_add_file(jcr, ff_pkt, NULL); /* list skipped files */
-       return 1;
-    case FT_ISARCH:
-       Jmsg(jcr, M_NOTSAVED, 0, _("     Archive file not saved: %s\n"), ff_pkt->fname);
-+      accurate_add_file(jcr, ff_pkt, NULL); /* list skipped files */
-       return 1;
-    case FT_NOOPEN: {
-       berrno be;
-@@ -1111,6 +1232,9 @@
-    }
-    unstrip_path(ff_pkt);
-+   /* list backuped files */
-+   accurate_add_file(jcr, ff_pkt, attribs);
-+
-    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"),
-@@ -1121,6 +1245,58 @@
-    return true;
- }
-+static bool encode_and_send_deleted_file(JCR *jcr, char *fname) 
-+{
-+   BSOCK *sd = jcr->store_bsock;
-+   char *attribs;
-+   char *attribsEx;
-+   int stat;
-+#ifdef FD_NO_SEND_TEST
-+   return true;
-+#endif
-+
-+   attribs = " ";
-+   attribsEx = " ";
-+
-+   /*
-+    * Send Attributes header to Storage daemon
-+    *    <file-index> <stream> <info>
-+    */
-+   if (!sd->fsend("%ld %d 0", 0, STREAM_UNIX_ATTRIBUTES)) {
-+      Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
-+            sd->bstrerror());
-+      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.
-+    */
-+   stat = sd->fsend("%ld %d %s%c%s%c%s%c%s%c", 
-+                  0 /* FileIndex */,
-+                  FT_NOSTAT /* FileType */,
-+                  fname /* FileName */, 
-+                  0, attribs, 0, 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"),
-+            sd->bstrerror());
-+      return false;
-+   }
-+   sd->signal(BNET_EOD);            /* indicate end of attributes data */
-+   return true;
-+}
-+
- /* 
-  * Do in place strip of path
-  */
-Index: src/filed/job.c
-===================================================================
---- src/filed/job.c    (révision 6372)
-+++ src/filed/job.c    (copie de travail)
-@@ -1087,6 +1087,9 @@
-       case 'c':
-          fo->flags |= FO_CHKCHANGES;
-          break;
-+      case 'C':
-+         fo->flags |= FO_ACCURATE;
-+         break;
-       default:
-          Emsg1(M_ERROR, 0, _("Unknown include/exclude option: %c\n"), *p);
-          break;
-@@ -1195,6 +1198,9 @@
-    level = get_memory(dir->msglen+1);
-    Dmsg1(110, "level_cmd: %s", dir->msg);
-+   if (strstr(dir->msg, "accurate")) {
-+      jcr->accurate = true;
-+   }
-    if (sscanf(dir->msg, "level = %s ", level) != 1) {
-       goto bail_out;
-    }
-@@ -1204,14 +1210,14 @@
-    /* Full backup requested? */
-    } else if (strcmp(level, "full") == 0) {
-       jcr->JobLevel = L_FULL;
--   } else if (strcmp(level, "differential") == 0) {
-+   } else if (strstr(level, "differential")) {
-       jcr->JobLevel = L_DIFFERENTIAL;
-       free_memory(level);
-       return 1;
--   } else if (strcmp(level, "incremental") == 0) {
-+   } else if (strstr(level, "incremental")) {
-       jcr->JobLevel = L_INCREMENTAL;
-       free_memory(level);
--      return 1;   
-+      return 1;
-    /*
-     * We get his UTC since time, then sync the clocks and correct it
-     *   to agree with our clock.
-Index: src/cats/sql_update.c
-===================================================================
---- src/cats/sql_update.c      (révision 6372)
-+++ src/cats/sql_update.c      (copie de travail)
-@@ -88,6 +88,102 @@
-    return stat;
- }
-+int db_accurate_delete_file_record(JCR *jcr, B_DB *mdb, FileId_t FileId, JobId_t BackupId)
-+{
-+   int stat;
-+   char ed1[50], ed2[50];
-+   db_lock(mdb);
-+   Mmsg(mdb->cmd, "DELETE FROM CurrentFile WHERE FileId=%s AND BackupId=%s",
-+      edit_int64(FileId, ed1), edit_int64(BackupId, ed2));
-+   stat = INSERT_DB(jcr, mdb, mdb->cmd);
-+   db_unlock(mdb);
-+   return stat;
-+}
-+
-+int db_accurate_mark_file_for_backup(JCR *jcr, B_DB *mdb, char *fname, JobId_t JobId)
-+{
-+   int stat;
-+   char ed1[50];
-+   db_lock(mdb);
-+   /* TODO: mdb->esc_xxx are already ok but it's more smart to recompute it */
-+//   mdb->esc_name = check_pool_memory_size(mdb->esc_name, 2*len+2);
-+//   mdb->esc_name = db_escape_string(jcr, mdb, mdb->esc_name, fname, len);
-+   Mmsg(mdb->cmd, "INSERT INTO ToBackup%s (name) VALUES ('%s%s')", edit_int64(JobId, ed1), mdb->esc_path, mdb->esc_name);
-+   stat = INSERT_DB(jcr, mdb, mdb->cmd);
-+   db_unlock(mdb);
-+   return stat;
-+}
-+
-+int db_accurate_cleanup_currentfile(JCR *jcr, B_DB *mdb, JobId_t BackupId)
-+{
-+   int stat;
-+   char ed1[50];
-+   db_lock(mdb);
-+   Mmsg(mdb->cmd, "DELETE FROM CurrentFile WHERE BackupId=%s", edit_int64(BackupId, ed1));
-+   stat = QUERY_DB(jcr, mdb, mdb->cmd);
-+   db_unlock(mdb);
-+   return stat;
-+}
-+
-+int db_accurate_update_currentfile(JCR *jcr, B_DB *mdb, JobId_t JobId, int JobLevel, JobId_t BackupId)
-+{
-+   int stat;
-+   char ed1[50], ed2[50], ed3[50];
-+   db_lock(mdb);
-+   edit_int64(JobId, ed2);
-+   Mmsg(mdb->cmd, 
-+      "INSERT INTO CurrentFile (FileId, BackupId, FullMark, MarkId) "
-+      " (SELECT FileId, %s, '%c', %s FROM File WHERE JobId=%s)", 
-+      edit_int64(BackupId, ed1),
-+      JobLevel, ed2, ed2);
-+   stat = QUERY_DB(jcr, mdb, mdb->cmd);
-+   db_unlock(mdb);
-+   return stat; 
-+}
-+
-+int db_accurate_create_tobackup_table(JCR *jcr, B_DB *mdb, JobId_t JobId)
-+{
-+   int stat;
-+   char ed1[50];
-+   db_lock(mdb);
-+   Mmsg(mdb->cmd, "CREATE TABLE ToBackup%s (name text)", edit_int64(JobId, ed1));
-+//   Mmsg(mdb->cmd, "CREATE TEMPORARY TABLE ToBackup%s (name text)", edit_int64(JobId, ed1));
-+   stat = QUERY_DB(jcr, mdb, mdb->cmd);
-+   db_unlock(mdb);
-+   return stat;
-+}
-+
-+int db_accurate_drop_tobackup_table(JCR *jcr, B_DB *mdb, JobId_t JobId)
-+{
-+   int stat=0;
-+   char ed1[50];
-+   db_lock(mdb);
-+//   Mmsg(mdb->cmd, "DROP TABLE ToBackup%s", edit_int64(JobId, ed1));
-+//   stat = QUERY_DB(jcr, mdb, mdb->cmd);
-+   db_unlock(mdb);
-+   return stat;
-+}
-+
-+
-+/* Mark the file record as being visited during database
-+ * accurate compare. Stuff JobId into the MarkId field
-+ */
-+int db_accurate_mark_file_record(JCR *jcr, B_DB *mdb, JobId_t BackupId, FileId_t FileId, JobId_t JobId)
-+{
-+   int stat;
-+   char ed1[50], ed2[50], ed3[50];
-+
-+   db_lock(mdb);
-+   Mmsg(mdb->cmd, "UPDATE CurrentFile SET MarkId=%s WHERE FileId=%s AND BackupId=%s", 
-+      edit_int64(JobId, ed1), edit_int64(FileId, ed2), edit_int64(BackupId, ed3));
-+   stat = QUERY_DB(jcr, mdb, mdb->cmd);
-+   if (!stat || sql_affected_rows(mdb) != 1) {
-+      stat = 0;
-+   }
-+   db_unlock(mdb);
-+   return stat;
-+}
-+
- /*
-  * Update the Job record at start of Job
-  *
-Index: src/cats/drop_postgresql_tables.in
-===================================================================
---- src/cats/drop_postgresql_tables.in (révision 6372)
-+++ src/cats/drop_postgresql_tables.in (copie de travail)
-@@ -5,7 +5,7 @@
- bindir=@SQL_BINDIR@
- db_name=@db_name@
--$bindir/psql -f - -d ${db_name} $* <<END-OF-DATA
-+$bindir/psql -f - -U regress -d ${db_name} $* <<END-OF-DATA
- drop table unsavedfiles;
- drop table basefiles;
- drop table jobmedia;
-Index: src/cats/make_postgresql_tables.in
-===================================================================
---- src/cats/make_postgresql_tables.in (révision 6372)
-+++ src/cats/make_postgresql_tables.in (copie de travail)
-@@ -5,7 +5,7 @@
- bindir=@SQL_BINDIR@
- db_name=@db_name@
--$bindir/psql -f - -d ${db_name} $* <<END-OF-DATA
-+$bindir/psql -f - -U regress -d ${db_name} $* <<END-OF-DATA
- CREATE TABLE filename
- (
-@@ -43,6 +43,59 @@
- CREATE INDEX file_jobid_idx on file (jobid);
- CREATE INDEX file_fp_idx on file (filenameid, pathid);
-+CREATE TABLE CurrentBackupId
-+(
-+     BackupId          serial     not null,
-+     ClientId          integer    not null,
-+     JobName           text       not null,
-+     FileSetId         integer    not null,
-+     primary key (BackupId)
-+);
-+
-+-- Serait bien de prendre la meme table pour
-+-- les File et le CurrentBackup...
-+-- Mais y'a des problemes pour les prunes
-+
-+CREATE TABLE CurrentFile
-+(
-+     FileId           integer    not null,
-+     BackupId         integer    not null,
-+     FullMark         char(1)    default 0,
-+     MarkId           integer    default 0,
-+     primary key (FileId)
-+);
-+
-+CREATE INDEX currentfile_fileid on CurrentFile (BackupId);
-+
-+-- CREATE TEMPORARY TABLE batch (fileindex int,
-+--                               jobid int,
-+--                               path varchar,
-+--                               name varchar,
-+--                               lstat varchar,
-+--                               md5 varchar);
-+-- 
-+-- -- On batch insert dans la table temporaire
-+
-+-- il faut trouver les fichiers manquant
-+-- INSERT des nouveaux, UPDATE des anciens, SELECT pour trouver les deletes
-+
-+
-+-- il faut trouver les fichiers modifies
-+-- Le champs LStat n'est plus le meme
-+-- SELECT * 
-+--   FROM CurrentBackup, 
-+--        batch JOIN Path USING (Path) JOIN Filename USING (Name)
-+--  WHERE Path.PathId = CurrentBackup.PathId
-+--    AND Filename.FilenameId = CurrentBackup.FilenameId
-+--    AND CurrentBackup.LStat != batch.LStat
-+-- 
-+-- il faut mettre a jour la liste des fichiers
-+
-+
-+
-+
-+
-+
- --
- -- Possibly add one or more of the following indexes
- --  if your Verifies are too slow.
-Index: src/cats/protos.h
-===================================================================
---- src/cats/protos.h  (révision 6372)
-+++ src/cats/protos.h  (copie de travail)
-@@ -78,14 +78,17 @@
- /* sql_delete.c */
- int db_delete_pool_record(JCR *jcr, B_DB *db, POOL_DBR *pool_dbr);
- int db_delete_media_record(JCR *jcr, B_DB *mdb, MEDIA_DBR *mr);
-+int db_accurate_clean_deleted_files(JCR *jcr, B_DB *mdb, JobId_t JobId, JobId_t BackupId);
- /* sql_find.c */
- bool db_find_job_start_time(JCR *jcr, B_DB *mdb, JOB_DBR *jr, POOLMEM **stime);
- bool db_find_last_jobid(JCR *jcr, B_DB *mdb, const char *Name, JOB_DBR *jr);
-+JobId_t db_accurate_find_backupid(JCR *jcr, B_DB *mdb, JOB_DBR *jr);
- int db_find_next_volume(JCR *jcr, B_DB *mdb, int index, bool InChanger, MEDIA_DBR *mr);
- bool db_find_failed_job_since(JCR *jcr, B_DB *mdb, JOB_DBR *jr, POOLMEM *stime, int &JobLevel);
- /* sql_get.c */
-+int db_accurate_get_file_attributes_record(JCR *jcr, B_DB *mdb, char *fname, JobId_t backupid, FILE_DBR *fdbr);
- bool db_get_pool_record(JCR *jcr, B_DB *db, POOL_DBR *pdbr);
- int db_get_client_record(JCR *jcr, B_DB *mdb, CLIENT_DBR *cr);
- bool db_get_job_record(JCR *jcr, B_DB *mdb, JOB_DBR *jr);
-@@ -129,6 +132,14 @@
- int  db_update_counter_record(JCR *jcr, B_DB *mdb, COUNTER_DBR *cr);
- int  db_add_digest_to_file_record(JCR *jcr, B_DB *mdb, FileId_t FileId, char *digest, int type);
- int  db_mark_file_record(JCR *jcr, B_DB *mdb, FileId_t FileId, JobId_t JobId);
-+int db_accurate_mark_file_for_backup(JCR *jcr, B_DB *mdb, char *fname, FileId_t JobId);
-+int db_accurate_mark_file_record(JCR *jcr, B_DB *mdb, JobId_t BackupId, FileId_t FileId, JobId_t JobId);
-+int db_accurate_drop_tobackup_table(JCR *jcr, B_DB *mdb, JobId_t JobId);
-+int db_accurate_create_tobackup_table(JCR *jcr, B_DB *mdb, JobId_t JobId);
-+int db_accurate_delete_file_record(JCR *jcr, B_DB *mdb, FileId_t FileId, JobId_t BackupId);
- void db_make_inchanger_unique(JCR *jcr, B_DB *mdb, MEDIA_DBR *mr);
-+int db_accurate_cleanup_currentfile(JCR *jcr, B_DB *mdb, JobId_t BackupId);
-+int db_accurate_update_currentfile(JCR *jcr, B_DB *mdb, JobId_t JobId, int JobLevel, JobId_t BackupId);
-+
- #endif /* __SQL_PROTOS_H */
-Index: src/cats/sql_find.c
-===================================================================
---- src/cats/sql_find.c        (révision 6372)
-+++ src/cats/sql_find.c        (copie de travail)
-@@ -190,7 +190,64 @@
-    return true;
- }
-+/*
-+ * Find BackupId of last job that ran.  E.g. for
-+ *
-+ * Returns: Last backuip
-+ *
-+ */
-+JobId_t
-+db_accurate_find_backupid(JCR *jcr, B_DB *mdb, JOB_DBR *jr)
-+{
-+   SQL_ROW row;
-+   char ed1[50],ed2[50];
-+   JobId_t backupid=0;
-+   if (jcr->accurate == false) {
-+      return 0;
-+   }
-+
-+   /* Find backupid */
-+   db_lock(mdb);
-+   Dmsg2(100, "JobLevel=%d JobType=%d\n", jcr->JobLevel, jcr->JobType);
-+   Mmsg(mdb->cmd,
-+"SELECT BackupId FROM CurrentBackupId WHERE JobName='%s' AND "
-+"ClientId=%s AND FileSetId=%s ORDER BY BackupId DESC LIMIT 1",
-+      jr->Name, 
-+      edit_int64(jr->ClientId, ed1),
-+      edit_int64(jr->FileSetId, ed2));
-+
-+   Dmsg1(100, "Query: %s\n", mdb->cmd);
-+   if (!QUERY_DB(jcr, mdb, mdb->cmd)) {
-+      db_unlock(mdb);
-+      return 0;
-+   }
-+   if ((row = sql_fetch_row(mdb)) == NULL) {
-+      sql_free_result(mdb);
-+      if (jcr->JobLevel == L_FULL) {
-+       Mmsg(mdb->cmd,
-+            "INSERT INTO CurrentBackupId (JobName, ClientId, FileSetId) VALUES ('%s', %s, %s)",
-+            jr->Name, ed1, ed2);
-+       if (!INSERT_DB(jcr, mdb, mdb->cmd)) {
-+          db_unlock(mdb);
-+          return 0;
-+       }
-+       backupid = sql_insert_id(mdb, NT_("CurrentBackupId"));
-+      } else {
-+       Mmsg1(&mdb->errmsg, _("No Job found for: %s.\n"), mdb->cmd);
-+       backupid = 0;
-+      }
-+   } else {
-+      backupid = str_to_int64(row[0]);
-+   }
-+
-+   sql_free_result(mdb);
-+
-+   db_unlock(mdb);
-+   return backupid;
-+}
-+
-+
- /*
-  * Find JobId of last job that ran.  E.g. for
-  *   VERIFY_CATALOG we want the JobId of the last INIT.
-Index: src/cats/sql_delete.c
-===================================================================
---- src/cats/sql_delete.c      (révision 6372)
-+++ src/cats/sql_delete.c      (copie de travail)
-@@ -236,5 +236,22 @@
-    return 1;
- }
-+/*
-+ * Purge delete file from CurrentFile table. This table contains only
-+ * current files.
-+ */
-+int db_accurate_clean_deleted_files(JCR *jcr, B_DB *mdb, JobId_t JobId, JobId_t BackupId)
-+{
-+   int stat;
-+   char ed1[50], ed2[50];
-+   db_lock(mdb);
-+   Mmsg(mdb->cmd, "DELETE FROM CurrentFile WHERE MarkId!=%s AND BackupId=%s", 
-+      edit_int64(JobId, ed1), edit_int64(BackupId, ed2));
-+   stat = QUERY_DB(jcr, mdb, mdb->cmd);
-+   db_unlock(mdb);
-+   return stat;
-+}
-+
-+
- #endif /* HAVE_SQLITE3 || HAVE_MYSQL || HAVE_SQLITE || HAVE_POSTGRESQL*/
-Index: src/cats/sql_create.c
-===================================================================
---- src/cats/sql_create.c      (révision 6372)
-+++ src/cats/sql_create.c      (copie de travail)
-@@ -829,6 +829,14 @@
-    return true;
- }
-+bool db_accurate_insert(JCR *jcr, B_DB *mdb, bool saved, const char *fname, struct stat *stat)
-+{
-+   int len;
-+   split_path_and_file(jcr, mdb, fname);
-+   /* make like in Verify code */
-+   return true;
-+} 
-+
- /*
-  * Create File record in B_DB
-  *
-Index: src/cats/sql_get.c
-===================================================================
---- src/cats/sql_get.c (révision 6372)
-+++ src/cats/sql_get.c (copie de travail)
-@@ -66,6 +66,8 @@
-  *
-  *  Returns: 0 on failure
-  *           1 on success with the File record in FILE_DBR
-+ *
-+ * TODO: optimize this with only one query
-  */
- int db_get_file_attributes_record(JCR *jcr, B_DB *mdb, char *fname, JOB_DBR *jr, FILE_DBR *fdbr)
- {
-@@ -86,7 +88,73 @@
-    return stat;
- }
-+/*
-+ * Given a full filename (with path), look up the File record
-+ * (with attributes) in the database.
-+ *
-+ *  Returns: 0 on failure
-+ *           1 on success with the File record in FILE_DBR
-+ */
-+int db_accurate_get_file_attributes_record(JCR *jcr, B_DB *mdb, char *fname, 
-+                                         JobId_t backupid, FILE_DBR *fdbr)
-+{
-+   int stat=0;
-+   char ed1[50];
-+   SQL_ROW row;
-+   db_lock(mdb);
-+   split_path_and_file(jcr, mdb, fname);
-+
-+   mdb->esc_name = check_pool_memory_size(mdb->esc_name, 2*mdb->fnl+2);
-+   db_escape_string(jcr, mdb, mdb->esc_name, mdb->fname, mdb->fnl);
-+
-+   mdb->esc_path = check_pool_memory_size(mdb->esc_path, 2*mdb->pnl+2);
-+   db_escape_string(jcr, mdb, mdb->esc_path, mdb->path, mdb->pnl);
-+
-+   /* A file could be present more than one time in the same backup, so we use LIMIT 1 */
-+   Mmsg(mdb->cmd,
-+"SELECT FileId, LStat, MD5, FilenameId, PathId, FileIndex, CurrentFile.MarkId, JobId "
-+  "FROM File JOIN CurrentFile USING (FileId) "
-+            "JOIN Filename USING (FilenameId) "
-+            "JOIN Path     USING (PathId) "
-+ "WHERE Path.Path='%s' "
-+   "AND Filename.Name='%s' "
-+   "AND BackupId=%s "
-+   "ORDER BY FileId DESC LIMIT 1",
-+      mdb->esc_path,
-+      mdb->esc_name,
-+      edit_int64(backupid, ed1));
-+   
-+   Dmsg1(2,"get_file %s\n", mdb->cmd);
-+
-+   if (QUERY_DB(jcr, mdb, mdb->cmd)) {
-+      char ed1[30];
-+      mdb->num_rows = sql_num_rows(mdb);
-+      if (mdb->num_rows == 1) {
-+         if ((row = sql_fetch_row(mdb)) == NULL) {
-+            Mmsg1(mdb->errmsg, _("error fetching row: %s\n"), sql_strerror(mdb));
-+         } else {
-+          fdbr->FileId     = str_to_int64(row[0]);
-+            bstrncpy(fdbr->LStat, row[1], sizeof(fdbr->LStat));
-+            bstrncpy(fdbr->Digest, row[2], sizeof(fdbr->Digest));
-+          fdbr->FilenameId = str_to_int64(row[3]);
-+          fdbr->PathId     = str_to_int64(row[4]);
-+          fdbr->FileIndex  = str_to_int64(row[5]);
-+          fdbr->MarkId     = str_to_int64(row[6]);
-+          fdbr->JobId      = str_to_int64(row[7]);
-+          stat=1;
-+       }
-+      } 
-+      sql_free_result(mdb);
-+   } else {
-+      Mmsg(mdb->errmsg, _("File record: %s not found in Catalog for BackupId=%s.\n"), fname, ed1);
-+   }
-+
-+   db_unlock(mdb);
-+
-+   return stat;
-+}
-+
- /*
-  * Get a File record
-  * Returns: 0 on failure
-Index: src/stored/append.c
-===================================================================
---- src/stored/append.c        (révision 6372)
-+++ src/stored/append.c        (copie de travail)
-@@ -185,16 +185,18 @@
-       Dmsg2(890, "<filed: Header FilInx=%d stream=%d\n", file_index, stream);
--      if (!(file_index > 0 && (file_index == last_file_index ||
--          file_index == last_file_index + 1))) {
--         Jmsg0(jcr, M_FATAL, 0, _("File index from FD not positive or sequential\n"));
--         ok = false;
--         break;
-+      if (file_index != 0) {  /* TODO: handle file_index == 0 */
-+       if (!(file_index > 0 && (file_index == last_file_index ||
-+                                file_index == last_file_index + 1))) {
-+          Jmsg0(jcr, M_FATAL, 0, _("File index from FD not positive or sequential\n"));
-+          ok = false;
-+          break;
-+       }
-+       if (file_index != last_file_index) {
-+          jcr->JobFiles = file_index;
-+          last_file_index = file_index;
-+       }
-       }
--      if (file_index != last_file_index) {
--         jcr->JobFiles = file_index;
--         last_file_index = file_index;
--      }
-       /* Read data stream from the File daemon.
-        *  The data stream is just raw bytes
-@@ -212,24 +214,26 @@
-             stream_to_ascii(buf1, rec.Stream,rec.FileIndex),
-             rec.data_len);
--         while (!write_record_to_block(dcr->block, &rec)) {
--            Dmsg2(850, "!write_record_to_block data_len=%d rem=%d\n", rec.data_len,
--                       rec.remainder);
--            if (!write_block_to_device(dcr)) {
--               Dmsg2(90, "Got write_block_to_dev error on device %s. %s\n",
--                  dev->print_name(), dev->bstrerror());
--               ok = false;
--               break;
--            }
--         }
--         if (!ok) {
--            Dmsg0(400, "Not OK\n");
--            break;
--         }
--         jcr->JobBytes += rec.data_len;   /* increment bytes this job */
--         Dmsg4(850, "write_record FI=%s SessId=%d Strm=%s len=%d\n",
--            FI_to_ascii(buf1, rec.FileIndex), rec.VolSessionId,
--            stream_to_ascii(buf2, rec.Stream, rec.FileIndex), rec.data_len);
-+       if (file_index != 0) {
-+          while (!write_record_to_block(dcr->block, &rec)) {
-+             Dmsg2(850, "!write_record_to_block data_len=%d rem=%d\n", rec.data_len,
-+                   rec.remainder);
-+             if (!write_block_to_device(dcr)) {
-+                Dmsg2(90, "Got write_block_to_dev error on device %s. %s\n",
-+                      dev->print_name(), dev->bstrerror());
-+                ok = false;
-+                break;
-+             }
-+          }
-+          if (!ok) {
-+             Dmsg0(400, "Not OK\n");
-+             break;
-+          }
-+          jcr->JobBytes += rec.data_len;   /* increment bytes this job */
-+          Dmsg4(850, "write_record FI=%s SessId=%d Strm=%s len=%d\n",
-+                FI_to_ascii(buf1, rec.FileIndex), rec.VolSessionId,
-+                stream_to_ascii(buf2, rec.Stream, rec.FileIndex), rec.data_len);
-+       }
-          /* Send attributes and digest to Director for Catalog */
-          if (stream == STREAM_UNIX_ATTRIBUTES || stream == STREAM_UNIX_ATTRIBUTES_EX ||
-Index: src/findlib/find.h
-===================================================================
---- src/findlib/find.h (révision 6372)
-+++ src/findlib/find.h (copie de travail)
-@@ -108,6 +108,7 @@
- #define FO_ENHANCEDWILD (1<<23)       /* Enhanced wild card processing */
- #define FO_CHKCHANGES   (1<<24)       /* Check if file have been modified during backup */
- #define FO_STRIPPATH    (1<<25)       /* Check for stripping path */
-+#define FO_ACCURATE     (1<<26)       /* Accurate mode */
- struct s_included_file {
-    struct s_included_file *next;
-Index: patches/testing/project-accurate-backup.patch
-===================================================================
---- patches/testing/project-accurate-backup.patch      (révision 6410)
-+++ patches/testing/project-accurate-backup.patch      (copie de travail)
-@@ -75,7 +75,7 @@
-  
-  /* Commands sent to File daemon */
-  static char backupcmd[] = "backup\n";
--@@ -96,7 +97,443 @@
-+@@ -96,7 +97,450 @@
-     return true;
-  }
-  
-@@ -93,6 +93,11 @@
- +   return 0;
- +}
- +
-++bool db_get_jobids(JCR *jcr)
-++{
-++   
-++}
-++
- +bool accurate_send_current_files(JCR *jcr)
- +{
- +   char buf[MAXSTRING];
-@@ -108,6 +113,7 @@
- +                JOIN File USING (FileId)
- +   WHERE File.FileIndex > 0
- +
-++ DROP TABLE btemp2
- +
- +SELECT DISTINCT ON (PathId, FilenameId) FileIndex, Path, Name, LStat
- +  FROM File JOIN Filename USING (FilenameId) JOIN Path USING (PathId) WHERE JobId IN (40341)
-@@ -299,6 +305,15 @@
- +   char ed1[50], ed2[50];
- +
- +   bsnprintf(buf, sizeof(buf),
-++          "SELECT Name FROM ToBackup%s",
-++          edit_uint64(jcr->JobId, ed2));
-++
-++   /* missing_handler is called for each file found */
-++   Dmsg1(2, "display files to backup cmd=%s\n", buf);
-++   db_sql_query(jcr->db, buf, accurate_handler, (void *)jcr);
-++   jcr->file_bsock->signal(BNET_EOD);
-++
-++   bsnprintf(buf, sizeof(buf),
- +      "SELECT Path.Path,Filename.Name "
- +        "FROM CurrentFile "
- +             "JOIN File USING (FileId) "
-@@ -312,14 +327,6 @@
- +   db_sql_query(jcr->db, buf, accurate_handler, (void *)jcr);
- +   jcr->file_bsock->signal(BNET_EOD);
- +   
--+   bsnprintf(buf, sizeof(buf),
--+          "SELECT Name FROM ToBackup%s",
--+          edit_uint64(jcr->JobId, ed2));
--+   /* missing_handler is called for each file found */
--+   Dmsg1(2, "display files to backup cmd=%s\n", buf);
--+   db_sql_query(jcr->db, buf, accurate_handler, (void *)jcr);
--+   jcr->file_bsock->signal(BNET_EOD);
--+
- +   return 1;
- +}
- +
-@@ -519,7 +526,7 @@
-   * Do a backup of the specified FileSet
-   *
-   *  Returns:  false on failure
--@@ -231,9 +668,18 @@
-+@@ -231,9 +675,18 @@
-        goto bail_out;
-     }
-  
-@@ -538,18 +545,6 @@
-     if (stat == JS_Terminated) {
-        backup_cleanup(jcr, stat);
-        return true;
--Index: src/dird/job.c
--===================================================================
----- src/dird/job.c    (révision 6372)
--+++ src/dird/job.c    (copie de travail)
--@@ -979,6 +979,7 @@
--    jcr->spool_data = job->spool_data;
--    jcr->spool_size = job->spool_size;
--    jcr->write_part_after_job = job->write_part_after_job;
--+   jcr->accurate = job->accurate;
--    if (jcr->RestoreBootstrap) {
--       free(jcr->RestoreBootstrap);
--       jcr->RestoreBootstrap = NULL;
- Index: src/dird/inc_conf.c
- ===================================================================
- --- src/dird/inc_conf.c       (révision 6372)
-@@ -589,49 +584,15 @@
-     {NULL,       0,                      0}
-  };
-  
--Index: src/dird/dird_conf.c
--===================================================================
----- src/dird/dird_conf.c      (révision 6372)
--+++ src/dird/dird_conf.c      (copie de travail)
--@@ -319,6 +319,7 @@
--    {"selectionpattern", store_str, ITEM(res_job.selection_pattern), 0, 0, 0},
--    {"runscript", store_runscript, ITEM(res_job.RunScripts), 0, ITEM_NO_EQUALS, 0},
--    {"selectiontype", store_migtype, ITEM(res_job.selection_type), 0, 0, 0},
--+   {"accurate", store_bool, ITEM(res_job.accurate), 0,0,0},
--    {NULL, NULL, {0}, 0, 0, 0}
-- };
-- 
--@@ -618,6 +619,9 @@
--       if (res->res_job.spool_size) {
--          sendit(sock, _("     SpoolSize=%s\n"),        edit_uint64(res->res_job.spool_size, ed1));
--       }
--+      if (res->res_job.JobType == JT_BACKUP) {
--+      sendit(sock, _("     Accurate=%d\n"), res->res_job.accurate);
--+      }
--       if (res->res_job.JobType == JT_MIGRATE) {
--          sendit(sock, _("     SelectionType=%d\n"), res->res_job.selection_type);
--       }
--Index: src/dird/dird_conf.h
--===================================================================
----- src/dird/dird_conf.h      (révision 6372)
--+++ src/dird/dird_conf.h      (copie de travail)
--@@ -400,6 +400,7 @@
--    bool write_part_after_job;         /* Set to write part after job in SD */
--    bool enabled;                      /* Set if job enabled */
--    bool OptimizeJobScheduling;        /* Set if we should optimize Job scheduling */
--+   bool accurate;                     /* Set if it is an accurate backup job */
--    
--    MSGS      *messages;               /* How and where to send messages */
--    SCHED     *schedule;               /* When -- Automatic schedule */
- Index: src/filed/backup.c
- ===================================================================
- --- src/filed/backup.c        (révision 6372)
- +++ src/filed/backup.c        (copie de travail)
--@@ -48,8 +48,113 @@
-+@@ -48,8 +48,114 @@
-  static bool crypto_session_start(JCR *jcr);
-  static void crypto_session_end(JCR *jcr);
-  static bool crypto_session_send(JCR *jcr, BSOCK *sd);
--+static bool encode_and_send_deleted_files(JCR *jcr, char *fname);
-++static bool encode_and_send_deleted_file(JCR *jcr, char *fname);
-  
-  /*
- + * Called by save_file when accept/discard file for backup
-@@ -704,16 +665,17 @@
- +      return true;
- +   }
- +
--+   /* get deleted files */
--+   while (dir->recv() >= 0) {
--+      Dmsg1(1, "deleted = %s\n", dir->msg);
--+      encode_and_send_deleted_files(jcr, dir->msg); 
--+   }
- +   /* get missing files */
- +   while (dir->recv() >= 0) {
- +      Dmsg1(1, "missing = %s\n", dir->msg);
- +   }
--+   
-++
-++   /* get deleted files */
-++   while (dir->recv() >= 0) {
-++      Dmsg1(1, "deleted = %s\n", dir->msg);
-++      encode_and_send_deleted_file(jcr, dir->msg); 
-++   }
-++  
- +   return true;
- +}
- +
-@@ -741,7 +703,7 @@
-   * Find all the requested files and send them
-   * to the Storage daemon.
-   *
--@@ -66,7 +171,6 @@
-+@@ -66,7 +172,6 @@
-     BSOCK *sd;
-     bool ok = true;
-     // TODO landonf: Allow user to specify encryption algorithm
-@@ -749,7 +711,7 @@
-     sd = jcr->store_bsock;
-  
-     set_jcr_job_status(jcr, JS_Running);
--@@ -134,6 +238,20 @@
-+@@ -134,6 +239,20 @@
-        ok = false;                     /* error */
-        set_jcr_job_status(jcr, JS_ErrorTerminated);
-     }
-@@ -770,7 +732,7 @@
-  
-     free_pool_memory(jcr->acl_text);
-  
--@@ -355,9 +473,11 @@
-+@@ -355,9 +474,11 @@
-     case FT_DIRNOCHG:
-     case FT_NOCHG:
-        Jmsg(jcr, M_SKIPPED, 1, _("     Unchanged file skipped: %s\n"), ff_pkt->fname);
-@@ -782,7 +744,7 @@
-        return 1;
-     case FT_NOOPEN: {
-        berrno be;
--@@ -1111,6 +1231,9 @@
-+@@ -1111,6 +1232,9 @@
-     }
-     unstrip_path(ff_pkt);
-  
-@@ -792,11 +754,11 @@
-     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"),
--@@ -1121,6 +1244,58 @@
-+@@ -1121,6 +1245,58 @@
-     return true;
-  }
-  
--+static bool encode_and_send_deleted_files(JCR *jcr, char *fname) 
-++static bool encode_and_send_deleted_file(JCR *jcr, char *fname) 
- +{
- +   BSOCK *sd = jcr->store_bsock;
- +   char *attribs;
-@@ -1402,18 +1364,6 @@
-  
-           /* Send attributes and digest to Director for Catalog */
-           if (stream == STREAM_UNIX_ATTRIBUTES || stream == STREAM_UNIX_ATTRIBUTES_EX ||
--Index: src/jcr.h
--===================================================================
----- src/jcr.h (révision 6372)
--+++ src/jcr.h (copie de travail)
--@@ -208,6 +208,7 @@
--    B_DB *db_batch;                    /* database pointer for batch insert */
--    ATTR_DBR *ar;                      /* DB attribute record */
--    guid_list *id_list;                /* User/group id to name list */
--+   bool accurate;                     /* true if job is accurate */
-- 
--    void *plugin_ctx_list;             /* list of contexts for plugins */
--    void *plugin_ctx;                  /* current plugin context */
- Index: src/findlib/find.h
- ===================================================================
- --- src/findlib/find.h        (révision 6372)
diff --git a/bacula/patches/testing/project-accurate-backup.patch2 b/bacula/patches/testing/project-accurate-backup.patch2
deleted file mode 100644 (file)
index 01767e7..0000000
+++ /dev/null
@@ -1,1148 +0,0 @@
-Index: src/dird/fd_cmds.c
-===================================================================
---- src/dird/fd_cmds.c (révision 6471)
-+++ src/dird/fd_cmds.c (copie de travail)
-@@ -50,7 +50,7 @@
- static char filesetcmd[]  = "fileset%s\n"; /* set full fileset */
- static char jobcmd[]      = "JobId=%s Job=%s SDid=%u SDtime=%u Authorization=%s\n";
- /* Note, mtime_only is not used here -- implemented as file option */
--static char levelcmd[]    = "level = %s%s mtime_only=%d\n";
-+static char levelcmd[]    = "level = %s%s%s mtime_only=%d\n";
- static char runscript[]   = "Run OnSuccess=%u OnFailure=%u AbortOnError=%u When=%u Command=%s\n";
- static char runbeforenow[]= "RunBeforeNow\n";
-@@ -226,13 +226,12 @@
-    char ed1[50];
-    stime = str_to_utime(jcr->stime);
--   fd->fsend(levelcmd, NT_("since_utime "), edit_uint64(stime, ed1), 0);
-+   fd->fsend(levelcmd, "", NT_("since_utime "), edit_uint64(stime, ed1), 0);
-    while (bget_dirmsg(fd) >= 0) {  /* allow him to poll us to sync clocks */
-       Jmsg(jcr, M_INFO, 0, "%s\n", fd->msg);
-    }
- }
--
- /*
-  * Send level command to FD.
-  * Used for backup jobs and estimate command.
-@@ -240,24 +239,26 @@
- bool send_level_command(JCR *jcr)
- {
-    BSOCK   *fd = jcr->file_bsock;
-+   const char *accurate=jcr->job->accurate?"accurate_":"";
-+   const char *not_accurate="";
-    /*
-     * Send Level command to File daemon
-     */
-    switch (jcr->JobLevel) {
-    case L_BASE:
--      fd->fsend(levelcmd, "base", " ", 0);
-+      fd->fsend(levelcmd, not_accurate, "base", " ", 0);
-       break;
-    /* L_NONE is the console, sending something off to the FD */
-    case L_NONE:
-    case L_FULL:
--      fd->fsend(levelcmd, "full", " ", 0);
-+      fd->fsend(levelcmd, not_accurate, "full", " ", 0);
-       break;
-    case L_DIFFERENTIAL:
--      fd->fsend(levelcmd, "differential", " ", 0);
-+      fd->fsend(levelcmd, accurate, "differential", " ", 0);
-       send_since_time(jcr);
-       break;
-    case L_INCREMENTAL:
--      fd->fsend(levelcmd, "incremental", " ", 0);
-+      fd->fsend(levelcmd, accurate, "incremental", " ", 0);
-       send_since_time(jcr);
-       break;
-    case L_SINCE:
-Index: src/dird/backup.c
-===================================================================
---- src/dird/backup.c  (révision 6471)
-+++ src/dird/backup.c  (copie de travail)
-@@ -97,6 +97,65 @@
- }
- /*
-+ * Foreach files in currrent list, send "/path/fname\0LStat" to FD
-+ */
-+static int accurate_list_handler(void *ctx, int num_fields, char **row)
-+{
-+   JCR *jcr = (JCR *)ctx;
-+
-+   if (job_canceled(jcr)) {
-+      return 1;
-+   }
-+   
-+   if (row[2] > 0) {            /* discard when file_index == 0 */
-+      jcr->file_bsock->fsend("%s%s%c%s", row[0], row[1], 0, row[4]); 
-+   }
-+   return 0;
-+}
-+
-+/*
-+ * Send current file list to FD
-+ *    DIR -> FD : accurate files=xxxx
-+ *    DIR -> FD : /path/to/file\0Lstat
-+ *    DIR -> FD : /path/to/dir/\0Lstat
-+ *    ...
-+ *    DIR -> FD : EOD
-+ */
-+bool send_accurate_current_files(JCR *jcr)
-+{
-+   POOL_MEM buf;
-+
-+   if (jcr->accurate==false || job_canceled(jcr) || jcr->JobLevel==L_FULL) {
-+      return true;
-+   }
-+   POOLMEM *jobids = get_pool_memory(PM_FNAME);
-+   db_accurate_get_jobids(jcr, jcr->db, &jcr->jr, jobids);
-+
-+   if (*jobids == 0) {
-+      free_pool_memory(jobids);
-+      Jmsg(jcr, M_FATAL, 0, _("Cannot find previous jobids.\n"));
-+      return false;
-+   }
-+   Jmsg(jcr, M_INFO, 0, _("Sending Accurate information.\n"));
-+
-+   /* to be able to allocate the right size for htable */
-+   POOLMEM *nb = get_pool_memory(PM_FNAME);
-+   Mmsg(buf, "SELECT sum(JobFiles) FROM Job WHERE JobId IN (%s)",jobids);
-+   db_sql_query(jcr->db, buf.c_str(), db_get_int_handler, nb);
-+   jcr->file_bsock->fsend("accurate files=%s\n", nb); 
-+
-+   db_get_file_list(jcr, jcr->db, jobids, accurate_list_handler, (void *)jcr);
-+
-+   free_pool_memory(jobids);
-+   free_pool_memory(nb);
-+
-+   jcr->file_bsock->signal(BNET_EOD);
-+   /* TODO: use response() ? */
-+
-+   return true;
-+}
-+
-+/*
-  * Do a backup of the specified FileSet
-  *
-  *  Returns:  false on failure
-@@ -225,6 +284,14 @@
-       Jmsg(jcr, M_FATAL, 0, "%s", db_strerror(jcr->db));
-    }
-+   /*
-+    * If backup is in accurate mode, we send the list of
-+    * all files to FD.
-+    */
-+   if (!send_accurate_current_files(jcr)) {
-+      goto bail_out;
-+   }
-+
-    /* Send backup command */
-    fd->fsend(backupcmd);
-    if (!response(jcr, fd, OKbackup, "backup", DISPLAY_ERROR)) {
-@@ -475,6 +542,7 @@
- "  Software Compression:   %s\n"
- "  VSS:                    %s\n"
- "  Encryption:             %s\n"
-+"  Accurate:               %s\n"
- "  Volume name(s):         %s\n"
- "  Volume Session Id:      %d\n"
- "  Volume Session Time:    %d\n"
-@@ -506,8 +574,9 @@
-         edit_uint64_with_suffix(jcr->SDJobBytes, ec6),
-         kbps,
-         compress,
--        jcr->VSS?"yes":"no",
--        jcr->Encrypt?"yes":"no",
-+        jcr->VSS?_("yes"):_("no"),
-+        jcr->Encrypt?_("yes"):_("no"),
-+        jcr->accurate?_("yes"):_("no"),
-         jcr->VolumeName,
-         jcr->VolSessionId,
-         jcr->VolSessionTime,
-Index: src/dird/catreq.c
-===================================================================
---- src/dird/catreq.c  (révision 6471)
-+++ src/dird/catreq.c  (copie de travail)
-@@ -346,8 +346,8 @@
-  * Update File Attributes in the catalog with data
-  *  sent by the Storage daemon.  Note, we receive the whole
-  *  attribute record, but we select out only the stat packet,
-- *  VolSessionId, VolSessionTime, FileIndex, and file name
-- *  to store in the catalog.
-+ *  VolSessionId, VolSessionTime, FileIndex, file type, and 
-+ *  file name to store in the catalog.
-  */
- void catalog_update(JCR *jcr, BSOCK *bs)
- {
-@@ -357,6 +357,7 @@
-    uint32_t FileIndex;
-    uint32_t data_len;
-    char *p;
-+   int filetype;
-    int len;
-    char *fname, *attr;
-    ATTR_DBR *ar = NULL;
-@@ -415,6 +416,7 @@
-       p = jcr->attr - bs->msg + p;    /* point p into jcr->attr */
-       skip_nonspaces(&p);             /* skip FileIndex */
-       skip_spaces(&p);
-+      filetype = str_to_int32(p);     /* TODO: choose between unserialize and str_to_int32 */
-       skip_nonspaces(&p);             /* skip FileType */
-       skip_spaces(&p);
-       fname = p;
-@@ -425,7 +427,11 @@
-       Dmsg1(400, "dird<stored: attr=%s\n", attr);
-       ar->attr = attr;
-       ar->fname = fname;
--      ar->FileIndex = FileIndex;
-+      if (filetype == FT_DELETED) {
-+         ar->FileIndex = 0;     /* special value */
-+      } else {
-+         ar->FileIndex = FileIndex;
-+      }
-       ar->Stream = Stream;
-       ar->link = NULL;
-       if (jcr->mig_jcr) {
-Index: src/dird/ua_restore.c
-===================================================================
---- src/dird/ua_restore.c      (révision 6471)
-+++ src/dird/ua_restore.c      (copie de travail)
-@@ -1005,7 +1005,6 @@
-     * For display purposes, the same JobId, with different volumes may
-     * appear more than once, however, we only insert it once.
-     */
--   int items = 0;
-    p = rx->JobIds;
-    tree.FileEstimate = 0;
-    if (get_next_jobid_from_list(&p, &JobId) > 0) {
-@@ -1020,23 +1019,12 @@
-          tree.DeltaCount = rx->JobId/50; /* print 50 ticks */
-       }
-    }
--   for (p=rx->JobIds; get_next_jobid_from_list(&p, &JobId) > 0; ) {
--      char ed1[50];
--      if (JobId == last_JobId) {
--         continue;                    /* eliminate duplicate JobIds */
--      }
--      last_JobId = JobId;
--      ua->info_msg(_("\nBuilding directory tree for JobId %s ...  "), 
--         edit_int64(JobId, ed1));
--      items++;
--      /*
--       * Find files for this JobId and insert them in the tree
--       */
--      Mmsg(rx->query, uar_sel_files, edit_int64(JobId, ed1));
--      if (!db_sql_query(ua->db, rx->query, insert_tree_handler, (void *)&tree)) {
--         ua->error_msg("%s", db_strerror(ua->db));
--      }
-+   ua->info_msg(_("\nBuilding directory tree for JobId(s) %s ...  "),
-+                rx->JobIds);
-+
-+   if (!db_get_file_list(ua->jcr, ua->db, rx->JobIds, insert_tree_handler, (void *)&tree)) {
-+      ua->error_msg("%s", db_strerror(ua->db));
-    }
-    if (tree.FileCount == 0) {
-       ua->send_msg(_("\nThere were no files inserted into the tree, so file selection\n"
-@@ -1055,26 +1043,13 @@
-       }
-    } else {
-       char ec1[50];
--      if (items==1) {
--         if (tree.all) {
--            ua->info_msg(_("\n1 Job, %s files inserted into the tree and marked for extraction.\n"),
--              edit_uint64_with_commas(tree.FileCount, ec1));
--         }
--         else {
--            ua->info_msg(_("\n1 Job, %s files inserted into the tree.\n"),
--              edit_uint64_with_commas(tree.FileCount, ec1));
--         }
-+      if (tree.all) {
-+         ua->info_msg(_("\n%s files inserted into the tree and marked for extraction.\n"),
-+                      edit_uint64_with_commas(tree.FileCount, ec1));
-+      } else {
-+         ua->info_msg(_("\n%s files inserted into the tree.\n"),
-+                      edit_uint64_with_commas(tree.FileCount, ec1));
-       }
--      else {
--         if (tree.all) {
--            ua->info_msg(_("\n%d Jobs, %s files inserted into the tree and marked for extraction.\n"),
--              items, edit_uint64_with_commas(tree.FileCount, ec1));
--         }
--         else {
--            ua->info_msg(_("\n%d Jobs, %s files inserted into the tree.\n"),
--              items, edit_uint64_with_commas(tree.FileCount, ec1));
--         }
--      }
-       if (find_arg(ua, NT_("done")) < 0) {
-          /* Let the user interact in selecting which files to restore */
-Index: src/dird/inc_conf.c
-===================================================================
---- src/dird/inc_conf.c        (révision 6471)
-+++ src/dird/inc_conf.c        (copie de travail)
-@@ -96,6 +96,7 @@
- static RES_ITEM options_items[] = {
-    {"compression",     store_opts,    {0},     0, 0, 0},
-    {"signature",       store_opts,    {0},     0, 0, 0},
-+   {"accurate",        store_opts,    {0},     0, 0, 0},
-    {"verify",          store_opts,    {0},     0, 0, 0},
-    {"onefs",           store_opts,    {0},     0, 0, 0},
-    {"recurse",         store_opts,    {0},     0, 0, 0},
-@@ -137,6 +138,7 @@
-    INC_KW_DIGEST,
-    INC_KW_ENCRYPTION,
-    INC_KW_VERIFY,
-+   INC_KW_ACCURATE,
-    INC_KW_ONEFS,
-    INC_KW_RECURSE,
-    INC_KW_SPARSE,
-@@ -167,6 +169,7 @@
-    {"signature",   INC_KW_DIGEST},
-    {"encryption",  INC_KW_ENCRYPTION},
-    {"verify",      INC_KW_VERIFY},
-+   {"accurate",    INC_KW_ACCURATE},
-    {"onefs",       INC_KW_ONEFS},
-    {"recurse",     INC_KW_RECURSE},
-    {"sparse",      INC_KW_SPARSE},
-@@ -278,6 +281,12 @@
-       bstrncat(opts, lc->str, optlen);
-       bstrncat(opts, ":", optlen);         /* terminate it */
-       Dmsg3(900, "Catopts=%s option=%s optlen=%d\n", opts, option,optlen);
-+   } else if (keyword == INC_KW_ACCURATE) { /* special case */
-+      /* ***FIXME**** ensure these are in permitted set */
-+      bstrncat(opts, "C", optlen);         /* indicate Accurate */
-+      bstrncat(opts, lc->str, optlen);
-+      bstrncat(opts, ":", optlen);         /* terminate it */
-+      Dmsg3(900, "Catopts=%s option=%s optlen=%d\n", opts, option,optlen);
-    } else if (keyword == INC_KW_STRIPPATH) { /* another special case */
-       if (!is_an_integer(lc->str)) {
-          scan_err1(lc, _("Expected a strip path positive integer, got:%s:"), lc->str);
-Index: src/filed/backup.c
-===================================================================
---- src/filed/backup.c (révision 6484)
-+++ src/filed/backup.c (copie de travail)
-@@ -37,6 +37,7 @@
- #include "bacula.h"
- #include "filed.h"
-+#include "lib/htable.h"
- /* Forward referenced functions */
- int save_file(JCR *jcr, FF_PKT *ff_pkt, bool top_level);
-@@ -49,7 +50,255 @@
- static void crypto_session_end(JCR *jcr);
- static bool crypto_session_send(JCR *jcr, BSOCK *sd);
-+typedef struct CurFile {
-+   hlink link;
-+   char *fname;
-+   char *lstat;
-+   bool seen;
-+} CurFile;
-+
-+#define accurate_mark_file_as_seen(elt) ((elt)->seen = 1)
-+#define accurate_file_has_been_seen(elt) ((elt)->seen)
-+
- /*
-+ * This function is called for each file seen in fileset.
-+ * We check in file_list hash if fname have been backuped
-+ * the last time. After we can compare Lstat field. 
-+ * 
-+ */
-+/* TODO: tweak verify code to use the same function ?? */
-+bool accurate_check_file(JCR *jcr, FF_PKT *ff_pkt)
-+{
-+   char *p;
-+   int stat=false;
-+   struct stat statc;                 /* catalog stat */
-+   char *Opts_Digest;
-+   char *fname;
-+   CurFile *elt;
-+
-+   int32_t LinkFIc;
-+
-+   if (*ff_pkt->VerifyOpts) { /* use mtime + ctime checks by default */
-+      Opts_Digest = ff_pkt->VerifyOpts;
-+   } else {
-+      Opts_Digest = "cm"; 
-+   }
-+
-+   if (jcr->accurate == false || jcr->JobLevel == L_FULL) {
-+      return true;
-+   }
-+
-+   strip_path(ff_pkt);
-+ 
-+   if (S_ISDIR(ff_pkt->statp.st_mode)) {
-+      fname = ff_pkt->link;
-+   } else {
-+      fname = ff_pkt->fname;
-+   } 
-+
-+   elt = (CurFile *) jcr->file_list->lookup(fname);
-+
-+   if (!elt) {
-+      Dmsg1(500, "accurate %s = yes (not found)\n", fname);
-+      stat=true;
-+      goto bail_out;
-+   }
-+
-+   if (accurate_file_has_been_seen(elt)) {
-+      Dmsg1(500, "accurate %s = no (already seen)\n", fname);
-+      stat=false;
-+      goto bail_out;
-+   }
-+
-+   decode_stat(elt->lstat, &statc, &LinkFIc); /* decode catalog stat */
-+//   *do_Digest = CRYPTO_DIGEST_NONE;
-+
-+   for (p=Opts_Digest; *p; p++) {
-+      char ed1[30], ed2[30];
-+      switch (*p) {
-+      case 'i':                /* compare INODEs */
-+         if (statc.st_ino != ff_pkt->statp.st_ino) {
-+            Jmsg(jcr, M_SAVED, 0, _("%s      st_ino   differ. Cat: %s File: %s\n"), fname,
-+                 edit_uint64((uint64_t)statc.st_ino, ed1),
-+                 edit_uint64((uint64_t)ff_pkt->statp.st_ino, ed2));
-+            stat = true;
-+         }
-+         break;
-+      case 'p':                /* permissions bits */
-+         if (statc.st_mode != ff_pkt->statp.st_mode) {
-+            Jmsg(jcr, M_SAVED, 0, _("%s      st_mode  differ. Cat: %x File: %x\n"), fname,
-+                 (uint32_t)statc.st_mode, (uint32_t)ff_pkt->statp.st_mode);
-+            stat = true;
-+         }
-+         break;
-+//      case 'n':                /* number of links */
-+//         if (statc.st_nlink != ff_pkt->statp.st_nlink) {
-+//            Jmsg(jcr, M_SAVED, 0, _("%s      st_nlink differ. Cat: %d File: %d\n"), fname,
-+//                 (uint32_t)statc.st_nlink, (uint32_t)ff_pkt->statp.st_nlink);
-+//            stat = true;
-+//         }
-+//         break;
-+      case 'u':                /* user id */
-+         if (statc.st_uid != ff_pkt->statp.st_uid) {
-+            Jmsg(jcr, M_SAVED, 0, _("%s      st_uid   differ. Cat: %u File: %u\n"), fname,
-+                 (uint32_t)statc.st_uid, (uint32_t)ff_pkt->statp.st_uid);
-+            stat = true;
-+         }
-+         break;
-+      case 'g':                /* group id */
-+         if (statc.st_gid != ff_pkt->statp.st_gid) {
-+            Jmsg(jcr, M_SAVED, 0, _("%s      st_gid   differ. Cat: %u File: %u\n"), fname,
-+                 (uint32_t)statc.st_gid, (uint32_t)ff_pkt->statp.st_gid);
-+            stat = true;
-+         }
-+         break;
-+      case 's':                /* size */
-+         if (statc.st_size != ff_pkt->statp.st_size) {
-+            Jmsg(jcr, M_SAVED, 0, _("%s      st_size  differ. Cat: %s File: %s\n"), fname,
-+                 edit_uint64((uint64_t)statc.st_size, ed1),
-+                 edit_uint64((uint64_t)ff_pkt->statp.st_size, ed2));
-+            stat = true;
-+         }
-+         break;
-+//      case 'a':                /* access time */
-+//         if (statc.st_atime != ff_pkt->statp.st_atime) {
-+//            Jmsg(jcr, M_SAVED, 0, _("%s      st_atime differs\n"), fname);
-+//            stat = true;
-+//         }
-+//         break;
-+      case 'm':
-+         if (statc.st_mtime != ff_pkt->statp.st_mtime) {
-+            Jmsg(jcr, M_SAVED, 0, _("%s      st_mtime differs\n"), fname);
-+            stat = true;
-+         }
-+         break;
-+      case 'c':                /* ctime */
-+         if (statc.st_ctime != ff_pkt->statp.st_ctime) {
-+            Jmsg(jcr, M_SAVED, 0, _("%s      st_ctime differs\n"), fname);
-+            stat = true;
-+         }
-+         break;
-+      case 'd':                /* file size decrease */
-+         if (statc.st_size > ff_pkt->statp.st_size) {
-+            Jmsg(jcr, M_SAVED, 0, _("%s      st_size  decrease. Cat: %s File: %s\n"), fname,
-+                 edit_uint64((uint64_t)statc.st_size, ed1),
-+                 edit_uint64((uint64_t)ff_pkt->statp.st_size, ed2));
-+            stat = true;
-+         }
-+         break;
-+      case '5':                /* compare MD5 */
-+         Dmsg1(500, "set Do_MD5 for %s\n", ff_pkt->fname);
-+//       *do_Digest = CRYPTO_DIGEST_MD5;
-+         break;
-+      case '1':                 /* compare SHA1 */
-+//       *do_Digest = CRYPTO_DIGEST_SHA1;
-+         break;
-+      case ':':
-+      case 'V':
-+      default:
-+         break;
-+      }
-+   }
-+   accurate_mark_file_as_seen(elt);
-+   Dmsg2(500, "accurate %s = %i\n", fname, stat);
-+
-+bail_out:
-+   unstrip_path(ff_pkt);
-+   return stat;
-+}
-+
-+/* 
-+ * This function doesn't work very well with smartalloc
-+ * TODO: use bigbuffer from htable
-+ */
-+int accurate_cmd(JCR *jcr)
-+{
-+   BSOCK *dir = jcr->dir_bsock;
-+   int len;
-+   uint64_t nb;
-+   CurFile *elt=NULL;
-+
-+   if (jcr->accurate==false || job_canceled(jcr) || jcr->JobLevel==L_FULL) {
-+      return true;
-+   }
-+
-+   if (sscanf(dir->msg, "accurate files=%ld", &nb) != 1) {
-+      dir->fsend(_("2991 Bad accurate command\n"));
-+      return false;
-+   }
-+
-+   jcr->file_list = (htable *)malloc(sizeof(htable));
-+   jcr->file_list->init(elt, &elt->link, nb);
-+
-+   /*
-+    * buffer = sizeof(CurFile) + dirmsg
-+    * dirmsg = fname + lstat
-+    */
-+   /* get current files */
-+   while (dir->recv() >= 0) {
-+      len = strlen(dir->msg);
-+      if ((len+1) < dir->msglen) {
-+//       elt = (CurFile *)malloc(sizeof(CurFile));
-+//       elt->fname  = (char *) malloc(dir->msglen+1);
-+
-+         /* we store CurFile, fname and lstat in the same chunk */
-+         elt = (CurFile *)malloc(sizeof(CurFile)+dir->msglen+1);
-+         elt->fname  = (char *) elt+sizeof(CurFile);
-+         memcpy(elt->fname, dir->msg, dir->msglen);
-+         elt->fname[dir->msglen]='\0';
-+         elt->lstat = elt->fname + len + 1;
-+       elt->seen=0;
-+         jcr->file_list->insert(elt->fname, elt); 
-+         Dmsg2(500, "add fname=%s lstat=%s\n", elt->fname, elt->lstat);
-+      }
-+   }
-+
-+//   jcr->file_list->stats();
-+   /* TODO: send a EOM ?
-+   dir->fsend("2000 OK accurate\n");
-+    */
-+   return true;
-+}
-+
-+bool accurate_send_deleted_list(JCR *jcr)
-+{
-+   CurFile *elt;
-+   FF_PKT *ff_pkt;
-+
-+   int stream = STREAM_UNIX_ATTRIBUTES;
-+
-+   if (jcr->accurate == false || jcr->JobLevel == L_FULL) {
-+      goto bail_out;
-+   }
-+
-+   if (jcr->file_list == NULL) {
-+      goto bail_out;
-+   }
-+
-+   ff_pkt = init_find_files();
-+   ff_pkt->type = FT_DELETED;
-+
-+   foreach_htable (elt, jcr->file_list) {
-+      if (!accurate_file_has_been_seen(elt)) { /* already seen */
-+         Dmsg3(500, "deleted fname=%s lstat=%s seen=%i\n", elt->fname, elt->lstat, elt->seen);
-+         ff_pkt->fname = elt->fname;
-+         decode_stat(elt->lstat, &ff_pkt->statp, &ff_pkt->LinkFI); /* decode catalog stat */
-+         encode_and_send_attributes(jcr, ff_pkt, stream);
-+      }
-+//      Free(elt->fname);
-+   }
-+   term_find_files(ff_pkt);
-+bail_out:
-+   /* TODO: clean htable when this function is not reached ? */
-+   if (jcr->file_list) {
-+      jcr->file_list->destroy();
-+      free(jcr->file_list);
-+      jcr->file_list = NULL;
-+   }
-+   return true;
-+}
-+
-+/*
-  * Find all the requested files and send them
-  * to the Storage daemon.
-  *
-@@ -100,7 +349,7 @@
-     */
-    jcr->compress_buf_size = jcr->buf_size + ((jcr->buf_size+999) / 1000) + 30;
-    jcr->compress_buf = get_memory(jcr->compress_buf_size);
--
-+   
- #ifdef HAVE_LIBZ
-    z_stream *pZlibStream = (z_stream*)malloc(sizeof(z_stream));  
-    if (pZlibStream) {
-@@ -121,10 +370,13 @@
-       return false;
-    }
--   Dmsg1(300, "set_find_options ff=%p\n", jcr->ff);
-    set_find_options((FF_PKT *)jcr->ff, jcr->incremental, jcr->mtime);
--   Dmsg0(300, "start find files\n");
-+   /* in accurate mode, we overwrite the find_one check function */
-+   if (jcr->accurate) {
-+      set_find_changed_function((FF_PKT *)jcr->ff, accurate_check_file);
-+   } 
-+   
-    start_heartbeat_monitor(jcr);
-    jcr->acl_text = get_pool_memory(PM_MESSAGE);
-@@ -135,6 +387,8 @@
-       set_jcr_job_status(jcr, JS_ErrorTerminated);
-    }
-+   accurate_send_deleted_list(jcr);              /* send deleted list to SD  */
-+
-    free_pool_memory(jcr->acl_text);
-    stop_heartbeat_monitor(jcr);
-@@ -1102,7 +1356,9 @@
-     * For a directory, link is the same as fname, but with trailing
-     * slash. For a linked file, link is the link.
-     */
--   strip_path(ff_pkt);
-+   if (ff_pkt->type != FT_DELETED) { /* already stripped */
-+      strip_path(ff_pkt);
-+   }
-    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 = sd->fsend("%ld %d %s%c%s%c%s%c%s%c", jcr->JobFiles,
-@@ -1116,7 +1372,9 @@
-       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);
-    }
--   unstrip_path(ff_pkt);
-+   if (ff_pkt->type != FT_DELETED) {
-+      unstrip_path(ff_pkt);
-+   }
-    Dmsg2(300, ">stored: attr len=%d: %s\n", sd->msglen, sd->msg);
-    if (!stat) {
-Index: src/filed/job.c
-===================================================================
---- src/filed/job.c    (révision 6471)
-+++ src/filed/job.c    (copie de travail)
-@@ -49,6 +49,7 @@
- /* Imported functions */
- extern int status_cmd(JCR *jcr);
- extern int qstatus_cmd(JCR *jcr);
-+extern int accurate_cmd(JCR *jcr);
- /* Forward referenced functions */
- static int backup_cmd(JCR *jcr);
-@@ -106,6 +107,7 @@
-    {"RunBeforeJob", runbefore_cmd, 0},
-    {"RunAfterJob",  runafter_cmd,  0},
-    {"Run",          runscript_cmd, 0},
-+   {"accurate",     accurate_cmd, 0},
-    {NULL,       NULL}                  /* list terminator */
- };
-@@ -1057,6 +1059,16 @@
-          }
-          fo->VerifyOpts[j] = 0;
-          break;
-+      case 'C':                  /* accurate options */
-+         /* Copy Accurate Options */
-+         for (j=0; *p && *p != ':'; p++) {
-+            fo->AccurateOpts[j] = *p;
-+            if (j < (int)sizeof(fo->AccurateOpts) - 1) {
-+               j++;
-+            }
-+         }
-+         fo->AccurateOpts[j] = 0;
-+         break;
-       case 'P':                  /* strip path */
-          /* Get integer */
-          p++;                    /* skip P */
-@@ -1195,6 +1207,9 @@
-    level = get_memory(dir->msglen+1);
-    Dmsg1(110, "level_cmd: %s", dir->msg);
-+   if (strstr(dir->msg, "accurate")) {
-+      jcr->accurate = true;
-+   }
-    if (sscanf(dir->msg, "level = %s ", level) != 1) {
-       goto bail_out;
-    }
-@@ -1204,14 +1219,14 @@
-    /* Full backup requested? */
-    } else if (strcmp(level, "full") == 0) {
-       jcr->JobLevel = L_FULL;
--   } else if (strcmp(level, "differential") == 0) {
-+   } else if (strstr(level, "differential")) {
-       jcr->JobLevel = L_DIFFERENTIAL;
-       free_memory(level);
-       return 1;
--   } else if (strcmp(level, "incremental") == 0) {
-+   } else if (strstr(level, "incremental")) {
-       jcr->JobLevel = L_INCREMENTAL;
-       free_memory(level);
--      return 1;   
-+      return 1;
-    /*
-     * We get his UTC since time, then sync the clocks and correct it
-     *   to agree with our clock.
-Index: src/filed/restore.c
-===================================================================
---- src/filed/restore.c        (révision 6471)
-+++ src/filed/restore.c        (copie de travail)
-@@ -320,6 +320,11 @@
-             bclose(&rctx.bfd);
-          }
-+       /* TODO: manage deleted files */
-+       if (rctx.type == FT_DELETED) { /* deleted file */
-+          continue;
-+       }
-+
-          /*
-           * Unpack attributes and do sanity check them
-           */
-Index: src/cats/protos.h
-===================================================================
---- src/cats/protos.h  (révision 6471)
-+++ src/cats/protos.h  (copie de travail)
-@@ -102,6 +102,9 @@
- int db_get_client_record(JCR *jcr, B_DB *mdb, CLIENT_DBR *cdbr);
- int db_get_counter_record(JCR *jcr, B_DB *mdb, COUNTER_DBR *cr);
- bool db_get_query_dbids(JCR *jcr, B_DB *mdb, POOL_MEM &query, dbid_list &ids);
-+bool db_get_file_list(JCR *jcr, B_DB *mdb, char *jobids, DB_RESULT_HANDLER *result_handler, void *ctx);
-+bool db_accurate_get_jobids(JCR *jcr, B_DB *mdb, JOB_DBR *jr, POOLMEM *jobids);
-+int db_get_int_handler(void *ctx, int num_fields, char **row);
- /* sql_list.c */
-Index: src/cats/sql_get.c
-===================================================================
---- src/cats/sql_get.c (révision 6471)
-+++ src/cats/sql_get.c (copie de travail)
-@@ -898,8 +898,6 @@
-    return ok;
- }
--
--
- /* Get Media Record
-  *
-  * Returns: false: on failure
-@@ -1018,5 +1016,141 @@
-    return ok;
- }
-+/*
-+ * Find the last "accurate" backup state (that can take deleted files in account)
-+ * 1) Get all files with jobid in list (F subquery) 
-+ * 2) Take only the last version of each file (Temp subquery) => accurate list is ok
-+ * 3) Join the result to file table to get fileindex, jobid and lstat information
-+ *
-+ * TODO: On postgresql, this is done with
-+SELECT DISTINCT ON (PathId, FilenameId) FileIndex, Path, Name, LStat
-+  FROM File JOIN Filename USING (FilenameId) JOIN Path USING (PathId) WHERE JobId IN (40341)
-+ ORDER BY PathId, FilenameId, JobId DESC
-+ */
-+bool db_get_file_list(JCR *jcr, B_DB *mdb, char *jobids, 
-+                      DB_RESULT_HANDLER *result_handler, void *ctx)
-+{
-+   if (!*jobids) {
-+      db_lock(mdb);
-+      Mmsg(mdb->errmsg, _("ERR=JobIds are empty\n"));
-+      db_unlock(mdb);
-+      return false;
-+   }
-+   POOL_MEM buf (PM_MESSAGE);
-+   
-+   Mmsg(buf,
-+ "SELECT Path.Path, Filename.Name, File.FileIndex, File.JobId, File.LStat "
-+ "FROM ( "
-+  "SELECT max(FileId) as FileId, PathId, FilenameId "
-+    "FROM (SELECT FileId, PathId, FilenameId FROM File WHERE JobId IN (%s)) AS F "
-+   "GROUP BY PathId, FilenameId "
-+  ") AS Temp "
-+ "JOIN Filename ON (Filename.FilenameId = Temp.FilenameId) "
-+ "JOIN Path ON (Path.PathId = Temp.PathId) "
-+ "JOIN File ON (File.FileId = Temp.FileId) "
-+ "WHERE File.FileIndex > 0 ",
-+             jobids);
-+
-+   return db_sql_query(mdb, buf.c_str(), result_handler, ctx);
-+}
-+
-+
-+/* Full : do nothing
-+ * Differential : get the last full id
-+ * Incremental : get the last full + last diff + last incr(s) ids
-+ *
-+ * TODO: look and merge from ua_restore.c
-+ */
-+bool db_accurate_get_jobids(JCR *jcr, B_DB *mdb, 
-+                            JOB_DBR *jr, POOLMEM *jobids)
-+{
-+   char clientid[50], jobid[50], filesetid[50];
-+   char date[MAX_TIME_LENGTH];
-+
-+   POOL_MEM query (PM_FNAME);
-+   bstrutime(date, sizeof(date),  time(NULL) + 1);
-+   jobids[0]='\0';
-+
-+   /* First, find the last good Full backup for this job/client/fileset */
-+   Mmsg(query, 
-+"CREATE TEMPORARY TABLE btemp3%s AS "
-+ "SELECT JobId, StartTime, EndTime, JobTDate, PurgedFiles "
-+   "FROM Job JOIN FileSet USING (FileSetId) "
-+  "WHERE ClientId = %s "
-+    "AND Level='F' AND JobStatus='T' AND Type='B' "
-+    "AND StartTime<'%s' "
-+    "AND FileSet.FileSet=(SELECT FileSet FROM FileSet WHERE FileSetId = %s) "
-+  "ORDER BY Job.JobTDate DESC LIMIT 1",
-+        edit_uint64(jcr->JobId, jobid),
-+        edit_uint64(jr->ClientId, clientid),
-+        date,
-+        edit_uint64(jr->FileSetId, filesetid));
-+
-+   if (!db_sql_query(mdb, query.c_str(), NULL, NULL)) {
-+      return false;
-+   }
-+
-+   if (jr->JobLevel == L_INCREMENTAL) {
-+
-+      /* Now, find the last differential backup after the last full */
-+      Mmsg(query, 
-+"INSERT INTO btemp3%s (JobId, StartTime, EndTime, JobTDate, PurgedFiles) "
-+ "SELECT JobId, StartTime, EndTime, JobTDate, PurgedFiles "
-+   "FROM Job JOIN FileSet USING (FileSetId) "
-+  "WHERE ClientId = %s "
-+    "AND Level='D' AND JobStatus='T' AND Type='B' "
-+    "AND StartTime > (SELECT EndTime FROM btemp3%s ORDER BY EndTime DESC LIMIT 1) "
-+    "AND FileSet.FileSet= (SELECT FileSet FROM FileSet WHERE FileSetId = %s) "
-+  "ORDER BY Job.JobTDate DESC LIMIT 1 ",
-+           jobid,
-+           clientid,
-+           jobid,
-+           filesetid);
-+
-+      db_sql_query(mdb, query.c_str(), NULL, NULL);
-+
-+      /* We just have to take all incremental after the last Full/Diff */
-+      Mmsg(query, 
-+"INSERT INTO btemp3%s (JobId, StartTime, EndTime, JobTDate, PurgedFiles) "
-+ "SELECT JobId, StartTime, EndTime, JobTDate, PurgedFiles "
-+   "FROM Job JOIN FileSet USING (FileSetId) "
-+  "WHERE ClientId = %s "
-+    "AND Level='I' AND JobStatus='T' AND Type='B' "
-+    "AND StartTime > (SELECT EndTime FROM btemp3%s ORDER BY EndTime DESC LIMIT 1) "
-+    "AND FileSet.FileSet= (SELECT FileSet FROM FileSet WHERE FileSetId = %s) "
-+  "ORDER BY Job.JobTDate DESC ",
-+           jobid,
-+           clientid,
-+           jobid,
-+           filesetid);
-+      db_sql_query(mdb, query.c_str(), NULL, NULL);
-+   }
-+
-+   /* build a jobid list ie: 1,2,3,4 */
-+   Mmsg(query, "SELECT JobId FROM btemp3%s", jobid);
-+   db_sql_query(mdb, query.c_str(), db_get_int_handler, jobids);
-+   Dmsg1(1, "db_accurate_get_jobids=%s\n", jobids);
-+
-+   Mmsg(query, "DROP TABLE btemp3%s", jobid);
-+   db_sql_query(mdb, query.c_str(), NULL, NULL);
-+
-+   return true;
-+}
-+
-+/*
-+ * Use to build a string of int list from a query. "10,20,30"
-+ */
-+int db_get_int_handler(void *ctx, int num_fields, char **row)
-+{
-+   POOLMEM *ret = (POOLMEM *)ctx;
-+   if (num_fields == 1) {
-+      if (ret[0]) {
-+         pm_strcat(ret, ",");
-+      }
-+      pm_strcat(ret, row[0]);
-+   }
-+   return 0;
-+}
-+
- #endif /* HAVE_SQLITE3 || HAVE_MYSQL || HAVE_SQLITE || HAVE_POSTGRESQL || HAVE_DBI */
-Index: src/baconfig.h
-===================================================================
---- src/baconfig.h     (révision 6471)
-+++ src/baconfig.h     (copie de travail)
-@@ -277,6 +277,7 @@
- #define FT_INVALIDDT 20               /* Drive type not allowed for */
- #define FT_REPARSE   21               /* Win NTFS reparse point */
- #define FT_PLUGIN    22               /* Plugin generated filename */
-+#define FT_DELETED   23               /* Deleted file entry */
- /* Definitions for upper part of type word (see above). */
- #define AR_DATA_STREAM (1<<16)        /* Data stream id present */
-Index: src/stored/bextract.c
-===================================================================
---- src/stored/bextract.c      (révision 6471)
-+++ src/stored/bextract.c      (copie de travail)
-@@ -343,6 +343,12 @@
-          build_attr_output_fnames(jcr, attr);
-+       if (attr->type == FT_DELETED) { /* TODO: choose the right fname/ofname */
-+          Jmsg(jcr, M_INFO, 0, _("%s was deleted.\n"), attr->fname);
-+          extract = false;
-+          return true;
-+       }
-+
-          extract = false;
-          stat = create_file(jcr, attr, &bfd, REPLACE_ALWAYS);
-          switch (stat) {
-Index: src/stored/bscan.c
-===================================================================
---- src/stored/bscan.c (révision 6471)
-+++ src/stored/bscan.c (copie de travail)
-@@ -845,7 +845,11 @@
-    ar.ClientId = mjcr->ClientId;
-    ar.JobId = mjcr->JobId;
-    ar.Stream = rec->Stream;
--   ar.FileIndex = rec->FileIndex;
-+   if (type == FT_DELETED) {
-+      ar.FileIndex = 0;
-+   } else {
-+      ar.FileIndex = rec->FileIndex;
-+   }
-    ar.attr = ap;
-    if (dcr->VolFirstIndex == 0) {
-       dcr->VolFirstIndex = rec->FileIndex;
-Index: src/jcr.h
-===================================================================
---- src/jcr.h  (révision 6471)
-+++ src/jcr.h  (copie de travail)
-@@ -119,6 +119,7 @@
- /* Forward referenced structures */
- class JCR;
-+class htable;
- struct FF_PKT;
- struct B_DB;
- struct ATTR_DBR;
-@@ -318,6 +319,7 @@
-    CRYPTO_CTX crypto;                 /* Crypto ctx */
-    DIRRES* director;                  /* Director resource */
-    bool VSS;                          /* VSS used by FD */
-+   htable *file_list;                 /* Previous file list (accurate mode) */
- #endif /* FILE_DAEMON */
-Index: src/lib/Makefile.in
-===================================================================
---- src/lib/Makefile.in        (révision 6471)
-+++ src/lib/Makefile.in        (copie de travail)
-@@ -29,7 +29,7 @@
-         res.c rwlock.c scan.c serial.c sha1.c \
-         signal.c smartall.c rblist.c tls.c tree.c \
-         util.c var.c watchdog.c workq.c btimers.c \
--        address_conf.c pythonlib.c breg.c
-+        address_conf.c pythonlib.c breg.c htable.c
- LIBOBJS = attr.o base64.o berrno.o bsys.o bget_msg.o \
-@@ -42,7 +42,7 @@
-         res.o rwlock.o scan.o serial.o sha1.o \
-         signal.o smartall.o rblist.o tls.o tree.o \
-         util.o var.o watchdog.o workq.o btimers.o \
--        address_conf.o pythonlib.o breg.o
-+        address_conf.o pythonlib.o breg.o htable.o
- EXTRAOBJS = @OBJLIST@
-Index: src/lib/attr.c
-===================================================================
---- src/lib/attr.c     (révision 6471)
-+++ src/lib/attr.c     (copie de travail)
-@@ -242,6 +242,14 @@
-    char *p, *f;
-    guid_list *guid;
-+   if (attr->type == FT_DELETED) { /* TODO: change this to get last seen values */
-+      bsnprintf(buf, sizeof(buf),
-+              "----------   - -        -                - ---------- --------  %s\n", attr->ofname);
-+      Dmsg1(20, "%s", buf);
-+      Jmsg(jcr, M_RESTORED, 1, "%s", buf);
-+      return;
-+   }
-+
-    if (!jcr->id_list) {
-       jcr->id_list = new_guid_list();
-    }
-Index: src/findlib/create_file.c
-===================================================================
---- src/findlib/create_file.c  (révision 6471)
-+++ src/findlib/create_file.c  (copie de travail)
-@@ -389,6 +389,9 @@
-          return CF_CREATED;
-       }
-+   case FT_DELETED:
-+      Qmsg2(jcr, M_INFO, 0, _("Original file %s have been deleted: type=%d\n"), attr->fname, attr->type);
-+      break;
-    /* The following should not occur */
-    case FT_NOACCESS:
-    case FT_NOFOLLOW:
-Index: src/findlib/find.c
-===================================================================
---- src/findlib/find.c (révision 6471)
-+++ src/findlib/find.c (copie de travail)
-@@ -96,6 +96,13 @@
-   Dmsg0(100, "Leave set_find_options()\n");
- }
-+void
-+set_find_changed_function(FF_PKT *ff, bool check_fct(JCR *jcr, FF_PKT *ff))
-+{
-+   Dmsg0(1, "Enter set_find_changed_function()\n");
-+   ff->check_fct = check_fct;
-+}
-+
- /*
-  * For VSS we need to know which windows drives
-  * are used, because we create a snapshot of all used
-Index: src/findlib/find_one.c
-===================================================================
---- src/findlib/find_one.c     (révision 6471)
-+++ src/findlib/find_one.c     (copie de travail)
-@@ -258,6 +258,33 @@
- }
- /*
-+ * In incremental/diffential or accurate backup, we
-+ * say if the current file has changed.
-+ */
-+static bool check_changes(JCR *jcr, FF_PKT *ff_pkt)
-+{
-+   /* in special mode (like accurate backup), user can 
-+    * choose his comparison function.
-+    */
-+   if (ff_pkt->check_fct) {
-+      return ff_pkt->check_fct(jcr, ff_pkt);
-+   }
-+
-+   /* in normal modes (incr/diff), we use this default
-+    * behaviour
-+    */
-+   if (ff_pkt->incremental &&
-+       (ff_pkt->statp.st_mtime < ff_pkt->save_time &&
-+      ((ff_pkt->flags & FO_MTIMEONLY) ||
-+       ff_pkt->statp.st_ctime < ff_pkt->save_time))) 
-+   {
-+      return false;
-+   } 
-+
-+   return true;
-+}
-+
-+/*
-  * Find a single file.
-  * handle_file is the callback for handling the file.
-  * p is the filename
-@@ -327,22 +354,18 @@
-       }
-       ff_pkt->volhas_attrlist = volume_has_attrlist(fname);
-    }
--
-    /*
-     * If this is an Incremental backup, see if file was modified
-     * since our last "save_time", presumably the last Full save
-     * or Incremental.
-     */
--   if (ff_pkt->incremental && !S_ISDIR(ff_pkt->statp.st_mode)) {
--      Dmsg1(300, "Non-directory incremental: %s\n", ff_pkt->fname);
--      /* Not a directory */
--      if (ff_pkt->statp.st_mtime < ff_pkt->save_time
--          && ((ff_pkt->flags & FO_MTIMEONLY) ||
--              ff_pkt->statp.st_ctime < ff_pkt->save_time)) {
--         /* Incremental option, file not changed */
--         ff_pkt->type = FT_NOCHG;
--         return handle_file(jcr, ff_pkt, top_level);
--      }
-+   if (   ff_pkt->incremental 
-+       && !S_ISDIR(ff_pkt->statp.st_mode) 
-+       && !check_changes(jcr, ff_pkt)) 
-+   {
-+      Dmsg1(500, "Non-directory incremental: %s\n", ff_pkt->fname);
-+      ff_pkt->type = FT_NOCHG;
-+      return handle_file(jcr, ff_pkt, top_level);
-    }
- #ifdef HAVE_DARWIN_OS
-@@ -502,10 +525,7 @@
-       link[len] = 0;
-       ff_pkt->link = link;
--      if (ff_pkt->incremental &&
--          (ff_pkt->statp.st_mtime < ff_pkt->save_time &&
--             ((ff_pkt->flags & FO_MTIMEONLY) ||
--               ff_pkt->statp.st_ctime < ff_pkt->save_time))) {
-+      if (ff_pkt->incremental && !check_changes(jcr, ff_pkt)) {
-          /* Incremental option, directory entry not changed */
-          ff_pkt->type = FT_DIRNOCHG;
-       } else {
-Index: src/findlib/find.h
-===================================================================
---- src/findlib/find.h (révision 6471)
-+++ src/findlib/find.h (copie de travail)
-@@ -146,6 +146,7 @@
-    int GZIP_level;                    /* GZIP level */
-    int strip_path;                    /* strip path count */
-    char VerifyOpts[MAX_FOPTS];        /* verify options */
-+   char AccurateOpts[MAX_FOPTS];      /* accurate mode options */
-    alist regex;                       /* regex string(s) */
-    alist regexdir;                    /* regex string(s) for directories */
-    alist regexfile;                   /* regex string(s) for files */
-@@ -215,6 +216,7 @@
-    findFILESET *fileset;
-    int (*file_save)(JCR *, FF_PKT *, bool); /* User's callback */
-    int (*plugin_save)(JCR *, FF_PKT *, bool); /* User's callback */
-+   bool (*check_fct)(JCR *, FF_PKT *); /* optionnal user fct to check file changes */
-    /* Values set by accept_file while processing Options */
-    uint32_t flags;                    /* backup options */
-Index: src/findlib/protos.h
-===================================================================
---- src/findlib/protos.h       (révision 6471)
-+++ src/findlib/protos.h       (copie de travail)
-@@ -45,6 +45,7 @@
- /* From find.c */
- FF_PKT *init_find_files();
- void  set_find_options(FF_PKT *ff, int incremental, time_t mtime);
-+void set_find_changed_function(FF_PKT *ff, bool check_fct(JCR *jcr, FF_PKT *ff));
- int   find_files(JCR *jcr, FF_PKT *ff, int file_sub(JCR *, FF_PKT *ff_pkt, bool),
-                  int plugin_sub(JCR *, FF_PKT *ff_pkt, bool));
- int   match_files(JCR *jcr, FF_PKT *ff, int sub(JCR *, FF_PKT *ff_pkt, bool));
diff --git a/bacula/patches/testing/project-accurate-backup.sql b/bacula/patches/testing/project-accurate-backup.sql
deleted file mode 100644 (file)
index ae5181d..0000000
+++ /dev/null
@@ -1,70 +0,0 @@
-
-CREATE TABLE CurrentBackupId
-(
-     BackupId          serial     not null,
-     ClientId          integer    not null,
-     JobName           text       not null,
-     FileSetId         integer    not null,
-     primary key (BackupId)
-);
-
--- Serait bien de prendre la meme table pour
--- les File et le CurrentBackup...
--- Quand on prune, il faut purger ici aussi
-
-CREATE TABLE CurrentBackup
-(
-     FileId           integer    not null,
-     BackupId         integer    not null,
-     FullMark         char(1)    default 0,
-     MarkId           integer    default 0,
-     primary key (FileId)
-);
-
-CREATE INDEX currentbackup_fileid on CurrentBackup (BackupId);
-
--- On batch insert dans la table temporaire
-
--- il faut trouver les fichiers manquant
--- INSERT des nouveaux, UPDATE des anciens, SELECT pour trouver les deletes
-
--- UPDATE CurrentBackup SET MarkId = 1 
---  WHERE CurrentBackup.Id IN (
---        SELECT CurrentBackup.Id 
---          FROM      batch 
---               JOIN Filename USING (Name) 
---               JOIN Path     USING (Path)
---               JOIN CurrentBackup 
---                 ON (Filename.FilenameId = CurrentBackup.FilenameId 
---                     AND
---                     Path.PathId = CurrentBackup.PathId)
---          WHERE CurrentBackup.BackupId = 1
---      )
--- 
--- INSERT INTO CurrentBackup (BackupId, FullMark, PathId, FilenameId, LStat, MD5)
---   (SELECT CurrentBackup.BackupId, 'F', Path.PathId, Filename.FilenameId, 
---       batch.LStat, batch.MD5
---      FROM batch        
---           JOIN Path     USING (Path) 
---           JOIN Filename USING (Name) 
---           LEFT OUTER JOIN CurrentBackup 
---                 ON (Filename.FilenameId = CurrentBackup.FilenameId 
---                     AND Path.PathId = CurrentBackup.PathId 
---                     AND CurrentBackup.BackupId = 1)
---          WHERE BackupId IS NULL
---              
---   )
--- 
--- il faut trouver les fichiers modifies
--- Le champs LStat n'est plus le meme
--- SELECT * 
---   FROM      batch 
---        JOIN Path     USING (Path) 
---        JOIN Filename USING (Name) 
---        JOIN CurrentBackup USING (FilenameId, PathId)
--- 
---  WHERE CurrentBackup.LStat != batch.LStat
---    AND CurrentBackup.BackupId = 1
--- 
--- il faut mettre a jour la liste des fichiers
-
diff --git a/bacula/patches/testing/spoolsize_per_job.patch b/bacula/patches/testing/spoolsize_per_job.patch
deleted file mode 100644 (file)
index e909573..0000000
+++ /dev/null
@@ -1,159 +0,0 @@
-Index: src/dird/msgchan.c
-===================================================================
---- src/dird/msgchan.c (revision 5108)
-+++ src/dird/msgchan.c (working copy)
-@@ -51,7 +51,7 @@
- /* Commands sent to Storage daemon */
- static char jobcmd[]     = "JobId=%s job=%s job_name=%s client_name=%s "
-    "type=%d level=%d FileSet=%s NoAttr=%d SpoolAttr=%d FileSetMD5=%s "
--   "SpoolData=%d WritePartAfterJob=%d PreferMountedVols=%d\n";
-+   "SpoolData=%d SpoolSize=%s WritePartAfterJob=%d PreferMountedVols=%d\n";
- static char use_storage[] = "use storage=%s media_type=%s pool_name=%s "
-    "pool_type=%s append=%d copy=%d stripe=%d\n";
- static char use_device[] = "use device=%s\n";
-@@ -157,7 +157,7 @@
-    POOL_MEM job_name, client_name, fileset_name;
-    int copy = 0;
-    int stripe = 0;
--   char ed1[30];
-+   char ed1[30], ed2[30];
-    sd = jcr->store_bsock;
-    /*
-@@ -186,8 +186,9 @@
-               job_name.c_str(), client_name.c_str(), 
-               jcr->JobType, jcr->JobLevel,
-               fileset_name.c_str(), !jcr->pool->catalog_files,
--              jcr->job->SpoolAttributes, jcr->fileset->MD5, jcr->spool_data, 
--              jcr->write_part_after_job, jcr->job->PreferMountedVolumes);
-+              jcr->job->SpoolAttributes, jcr->fileset->MD5, jcr->spool_data,
-+              edit_int64(jcr->spool_size, ed2), jcr->write_part_after_job, 
-+              jcr->job->PreferMountedVolumes);
-    Dmsg1(100, ">stored: %s\n", sd->msg);
-    if (bget_dirmsg(sd) > 0) {
-        Dmsg1(100, "<stored: %s", sd->msg);
-Index: src/dird/job.c
-===================================================================
---- src/dird/job.c     (revision 5108)
-+++ src/dird/job.c     (working copy)
-@@ -927,6 +927,7 @@
-    jcr->fileset = job->fileset;
-    jcr->messages = job->messages;
-    jcr->spool_data = job->spool_data;
-+   jcr->spool_size = job->spool_size;
-    jcr->write_part_after_job = job->write_part_after_job;
-    if (jcr->RestoreBootstrap) {
-       free(jcr->RestoreBootstrap);
-Index: src/dird/dird_conf.c
-===================================================================
---- src/dird/dird_conf.c       (revision 5108)
-+++ src/dird/dird_conf.c       (working copy)
-@@ -295,6 +295,7 @@
-    {"enabled",     store_bool, ITEM(res_job.enabled), 0, ITEM_DEFAULT, true},
-    {"spoolattributes",store_bool, ITEM(res_job.SpoolAttributes), 0, ITEM_DEFAULT, false},
-    {"spooldata",   store_bool, ITEM(res_job.spool_data), 0, ITEM_DEFAULT, false},
-+   {"spoolsize",   store_size, ITEM(res_job.spool_size), 0, 0, 0},
-    {"rerunfailedlevels",   store_bool, ITEM(res_job.rerun_failed_levels), 0, ITEM_DEFAULT, false},
-    {"prefermountedvolumes", store_bool, ITEM(res_job.PreferMountedVolumes), 0, ITEM_DEFAULT, true},
-    {"runbeforejob", store_short_runscript,  ITEM(res_job.RunScripts),  0, 0, 0},
-@@ -600,6 +601,9 @@
-          res->res_job.RescheduleOnError, res->res_job.RescheduleTimes,
-          edit_uint64_with_commas(res->res_job.RescheduleInterval, ed1),
-          res->res_job.spool_data, res->res_job.write_part_after_job);
-+      if (res->res_job.spool_size) {
-+         sendit(sock, _("     SpoolSize=%s\n"),       edit_uint64(res->res_job.spool_size, ed1));
-+      }
-       if (res->res_job.JobType == JT_MIGRATE) {
-          sendit(sock, _("     SelectionType=%d\n"), res->res_job.selection_type);
-       }
-Index: src/dird/dird_conf.h
-===================================================================
---- src/dird/dird_conf.h       (revision 5108)
-+++ src/dird/dird_conf.h       (working copy)
-@@ -380,6 +380,7 @@
-    utime_t RescheduleInterval;        /* Reschedule interval */
-    utime_t JobRetention;              /* job retention period in seconds */
-    uint32_t MaxConcurrentJobs;        /* Maximum concurrent jobs */
-+   int64_t spool_size;                /* Size of spool file for this job */
-    int RescheduleTimes;               /* Number of times to reschedule job */
-    bool RescheduleOnError;            /* Set to reschedule on error */
-    bool PrefixLinks;                  /* prefix soft links with Where path */
-Index: src/stored/job.c
-===================================================================
---- src/stored/job.c   (revision 5108)
-+++ src/stored/job.c   (working copy)
-@@ -49,7 +49,7 @@
- /* Requests from the Director daemon */
- static char jobcmd[] = "JobId=%d job=%127s job_name=%127s client_name=%127s "
-       "type=%d level=%d FileSet=%127s NoAttr=%d SpoolAttr=%d FileSetMD5=%127s "
--      "SpoolData=%d WritePartAfterJob=%d PreferMountedVols=%d\n";
-+      "SpoolData=%d SpoolSize=%s WritePartAfterJob=%d PreferMountedVols=%d\n";
- /* Responses sent to Director daemon */
-@@ -73,6 +73,7 @@
- {
-    int JobId;
-    char auth_key[100];
-+   char spool_size[30];
-    BSOCK *dir = jcr->dir_bsock;
-    POOL_MEM job_name, client_name, job, fileset_name, fileset_md5;
-    int JobType, level, spool_attributes, no_attributes, spool_data;
-@@ -87,9 +88,9 @@
-    stat = sscanf(dir->msg, jobcmd, &JobId, job.c_str(), job_name.c_str(),
-               client_name.c_str(),
-               &JobType, &level, fileset_name.c_str(), &no_attributes,
--              &spool_attributes, fileset_md5.c_str(), &spool_data, 
-+              &spool_attributes, fileset_md5.c_str(), &spool_data, spool_size,
-               &write_part_after_job, &PreferMountedVols);
--   if (stat != 13) {
-+   if (stat != 14) {
-       pm_strcpy(jcr->errmsg, dir->msg);
-       bnet_fsend(dir, BAD_job, stat, jcr->errmsg);
-       Dmsg1(100, ">dird: %s", dir->msg);
-@@ -124,6 +125,7 @@
-    jcr->no_attributes = no_attributes;
-    jcr->spool_attributes = spool_attributes;
-    jcr->spool_data = spool_data;
-+   jcr->spool_size = str_to_int64(spool_size);
-    jcr->write_part_after_job = write_part_after_job;
-    jcr->fileset_md5 = get_pool_memory(PM_NAME);
-    pm_strcpy(jcr->fileset_md5, fileset_md5);
-Index: src/stored/acquire.c
-===================================================================
---- src/stored/acquire.c       (revision 5108)
-+++ src/stored/acquire.c       (working copy)
-@@ -609,7 +609,12 @@
-       if (dcr->attached_to_dev) {
-          detach_dcr_from_dev(dcr);
-       }
--      dcr->max_job_spool_size = dev->device->max_job_spool_size;
-+      /* Use job spoolsize prior to device spoolsize*/
-+      if (jcr->spool_size) {
-+       dcr->max_job_spool_size = jcr->spool_size;
-+      } else {
-+       dcr->max_job_spool_size = dev->device->max_job_spool_size;
-+      }
-       dcr->device = dev->device;
-       dcr->dev = dev;
-       attach_dcr_to_dev(dcr);
-Index: src/jcr.h
-===================================================================
---- src/jcr.h  (revision 5108)
-+++ src/jcr.h  (working copy)
-@@ -246,6 +246,7 @@
-    int replace;                       /* Replace option */
-    int NumVols;                       /* Number of Volume used in pool */
-    int reschedule_count;              /* Number of times rescheduled */
-+   int64_t spool_size;                /* Spool size for this job */
-    bool spool_data;                   /* Spool data in SD */
-    bool acquired_resource_locks;      /* set if resource locks acquired */
-    bool term_wait_inited;             /* Set when cond var inited */
-@@ -323,6 +324,7 @@
-    bool spool_attributes;             /* set if spooling attributes */
-    bool no_attributes;                /* set if no attributes wanted */
-    bool spool_data;                   /* set to spool data */
-+   int64_t spool_size;                /* Spool size for this job */
-    int CurVol;                        /* Current Volume count */
-    DIRRES* director;                  /* Director resource */
-    alist *write_store;                /* list of write storage devices sent by DIR */ 
diff --git a/bacula/patches/testing/spoolsize_per_job.readme b/bacula/patches/testing/spoolsize_per_job.readme
deleted file mode 100644 (file)
index cdc86d8..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-From: Eric Bollengier <eric at homelinux dot org>
-
-Add Job { SpoolSize = 10G } option
-This is very useful for big backup
-You must upgrade SD and DIR at the same time.
-
index 1c5fd5ab02332a71906c74993e8ff47d1629f013..a50001a0c6e14a97e5ebcb9627ede4f5c815d924 100644 (file)
@@ -1940,16 +1940,16 @@ static void store_runscript(LEX *lc, RES_ITEM *item, int index, int pass)
        */
       res_runscript.set_job_code_callback(job_code_callback_filesetname);
       while ((c=(char*)res_runscript.commands->pop()) != NULL) {
-        t = (int) res_runscript.commands->pop();
-        res_runscript.command = c;
-        res_runscript.cmd_type = t;
+         t = (int) res_runscript.commands->pop();
+         res_runscript.command = c;
+         res_runscript.cmd_type = t;
          RUNSCRIPT *script = new_runscript();
          memcpy(script, &res_runscript, sizeof(RUNSCRIPT));
-        /* target is taken from res_runscript, each runscript object have
-         * a copy 
-         */
-        script->target = NULL;
-        script->set_target(res_runscript.target);
+         /* target is taken from res_runscript, each runscript object have
+          * a copy 
+          */
+         script->target = NULL;
+         script->set_target(res_runscript.target);
 
          (*runscripts)->append(script);
          script->debug();