]> git.sur5r.net Git - bacula/bacula/commitdiff
ebl update accurate project
authorEric Bollengier <eric@eb.homelinux.org>
Tue, 5 Feb 2008 08:22:37 +0000 (08:22 +0000)
committerEric Bollengier <eric@eb.homelinux.org>
Tue, 5 Feb 2008 08:22:37 +0000 (08:22 +0000)
git-svn-id: https://bacula.svn.sourceforge.net/svnroot/bacula/trunk@6369 91ce42f0-d328-0410-95d8-f526ca767f89

bacula/patches/testing/project-accurate-backup.patch [new file with mode: 0644]
bacula/patches/testing/project-accurate-backup.sql [new file with mode: 0644]

diff --git a/bacula/patches/testing/project-accurate-backup.patch b/bacula/patches/testing/project-accurate-backup.patch
new file mode 100644 (file)
index 0000000..95a05fd
--- /dev/null
@@ -0,0 +1,583 @@
+Index: src/dird/backup.c
+===================================================================
+--- src/dird/backup.c  (révision 6368)
++++ 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";
+@@ -97,6 +98,286 @@
+ }
+ /*
++ * 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 missing_handler(void *ctx, int num_fields, char **row)
++{
++   JCR *jcr = (JCR *)ctx;
++
++   if (job_canceled(jcr)) {
++      return 1;
++   }
++
++   /* TODO: return the list to the FD */
++   Qmsg(jcr, M_INFO, 0, "      %s%s\n", row[0]?row[0]:"", row[1]?row[1]:"");
++   return 0;
++}
++
++/*
++ * 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 
++ *
++ *
++ */
++bool accurate_compute_files(JCR *jcr)
++{
++   BSOCK   *fd;
++   int n, len;
++   FILE_DBR fdbr;
++   struct stat statf;                 /* file stat */
++   struct stat statc;                 /* catalog stat */
++   int stat = JS_Terminated;
++   char buf[MAXSTRING];
++   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 */
++
++   memset(&fdbr, 0, sizeof(FILE_DBR));
++   fd = jcr->file_bsock;
++   fdbr.JobId = JobId;                
++   jcr->FileIndex = 0;
++
++   Dmsg0(20, "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)) {
++         return false;
++      }
++      fname = check_pool_memory_size(fname, fd->msglen);
++      jcr->fname = check_pool_memory_size(jcr->fname, fd->msglen);
++      Dmsg1(20, "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);
++         return false;
++      }
++      /*
++       * 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) {
++         int32_t LinkFIf, LinkFIc;
++         Dmsg2(400, "file_index=%d attr=%s\n", file_index, attr);
++         jcr->JobFiles++;
++         jcr->FileIndex = file_index;    /* remember attribute file_index */
++         decode_stat(attr, &statf, &LinkFIf);  /* decode file stat packet */
++         do_Digest = CRYPTO_DIGEST_NONE;
++         pm_strcpy(jcr->fname, fname);  /* move filename into JCR */
++
++         Dmsg3(040, "dird<filed: stream=%d %s %s\n", stream, jcr->fname, attr);
++
++         /*
++          * Find equivalent record in the database
++          */
++         fdbr.FileId = 0;
++//         if (!db_get_file_attributes_record(jcr, jcr->db, jcr->fname,
++//              &jcr->previous_jr, &fdbr)) {
++       if (1) {
++            Jmsg(jcr, M_INFO, 0, _("New file: %s\n"), jcr->fname);
++            Dmsg1(020, _("File not in catalog: %s\n"), jcr->fname);
++            continue;
++         } else {
++            /*
++             * mark file record as visited by stuffing the
++             * current JobId, which is unique, into the MarkId field.
++             */
++            db_mark_file_record(jcr, jcr->db, fdbr.FileId, jcr->JobId);
++         }
++
++         Dmsg3(400, "Found %s in catalog. inx=%d Opts=%s\n", jcr->fname,
++            file_index, Opts_Digest);
++         decode_stat(fdbr.LStat, &statc, &LinkFIc); /* decode catalog stat */
++
++       // TODO: for each JS_Differences, send it to FD for backup
++         /*
++          * Loop over options supplied by user and verify the
++          * fields he requests.
++          */
++         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 = JS_Differences;
++               }
++               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 = JS_Differences;
++               }
++               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 = JS_Differences;
++               }
++               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 = JS_Differences;
++               }
++               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 = JS_Differences;
++               }
++               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 = JS_Differences;
++               }
++               break;
++            case 'a':                /* access time */
++               if (statc.st_atime != statf.st_atime) {
++                  Jmsg(jcr, M_INFO, 0, _("      st_atime differs\n"));
++                  stat = JS_Differences;
++               }
++               break;
++            case 'm':
++               if (statc.st_mtime != statf.st_mtime) {
++                  Jmsg(jcr, M_INFO, 0, _("      st_mtime differs\n"));
++                  stat = JS_Differences;
++               }
++               break;
++            case 'c':                /* ctime */
++               if (statc.st_ctime != statf.st_ctime) {
++                  Jmsg(jcr, M_INFO, 0, _("      st_ctime differs\n"));
++                  stat = JS_Differences;
++               }
++               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 = JS_Differences;
++               }
++               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;
++            }
++         }
++      /*
++       * Got Digest Signature from Storage daemon
++       *  It came across in the Opts_Digest field.
++       */
++      } 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);
++            return false;
++         }
++         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());
++      return false;
++   }
++
++   /* Now find all the files that are missing -- i.e. all files in
++    *  the database where the MarkId != current JobId
++    */
++   bsnprintf(buf, sizeof(buf),
++      "SELECT Path.Path,Filename.Name FROM File,Path,Filename "
++      "WHERE File.JobId=%d "
++      "AND File.MarkId!=%d AND File.PathId=Path.PathId "
++      "AND File.FilenameId=Filename.FilenameId",
++         JobId, jcr->JobId);
++   /* missing_handler is called for each file found */
++   db_sql_query(jcr->db, buf, missing_handler, (void *)jcr);
++
++   free_pool_memory(fname);
++
++   return true;
++}
++
++/*
+  * Do a backup of the specified FileSet
+  *
+  *  Returns:  false on failure
+@@ -231,6 +512,13 @@
+       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 */
+Index: src/dird/inc_conf.c
+===================================================================
+--- src/dird/inc_conf.c        (révision 6368)
++++ 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/dird/dird_conf.c
+===================================================================
+--- src/dird/dird_conf.c       (révision 6368)
++++ 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},
++   {"accuratebackup", 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 6368)
++++ 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 6368)
++++ src/filed/backup.c (copie de travail)
+@@ -49,7 +49,84 @@
+ static void crypto_session_end(JCR *jcr);
+ static bool crypto_session_send(JCR *jcr, BSOCK *sd);
++#define backup_stat(x,y,z) (x.z = y.z ; y.z = 0)
++
+ /*
++ * 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) {
++      return true;
++   }
++
++   if (!stats) {
++      file_index=0;
++      encode_stat(attribs, ff_pkt, 0);
++      a = attribs;
++   }
++
++   if (ff_pkt->type == FT_LNK || ff_pkt->type == FT_LNKSAVED) {
++      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);
++   } else if (ff_pkt->type == FT_DIREND || ff_pkt->type == FT_REPARSE) {
++         /* Here link is the canonical filename (i.e. with trailing slash) */
++      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);
++   } else {
++      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);
++   }
++
++   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)
++{   
++   if (jcr->accurate == false || job_canceled(jcr)) {
++      return true;
++   }
++   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,6 +143,7 @@
+    BSOCK *sd;
+    bool ok = true;
+    // TODO landonf: Allow user to specify encryption algorithm
++   jcr->accurate=true;                /* TODO: remove that */
+    sd = jcr->store_bsock;
+@@ -135,6 +213,20 @@
+       set_jcr_job_status(jcr, JS_ErrorTerminated);
+    }
++   /* 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, (void *)jcr)) {
++//     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);
+    stop_heartbeat_monitor(jcr);
+@@ -355,9 +447,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;
+@@ -1109,6 +1203,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"),
+Index: src/filed/job.c
+===================================================================
+--- src/filed/job.c    (révision 6368)
++++ 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;
+Index: src/cats/sql_create.c
+===================================================================
+--- src/cats/sql_create.c      (révision 6368)
++++ 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/jcr.h
+===================================================================
+--- src/jcr.h  (révision 6368)
++++ 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;
+Index: src/findlib/find.h
+===================================================================
+--- src/findlib/find.h (révision 6368)
++++ 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;
diff --git a/bacula/patches/testing/project-accurate-backup.sql b/bacula/patches/testing/project-accurate-backup.sql
new file mode 100644 (file)
index 0000000..715d6f6
--- /dev/null
@@ -0,0 +1,83 @@
+
+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 CurrentBackup
+(
+     Id               serial     not null,
+     BackupId         integer    not null,
+     FullMark         char(1)    default 0,
+     PathId          integer    not null,
+     FilenameId              integer    not null,
+     MarkId          integer    not null  default 0,
+     LStat           text       not null,
+     md5             text       not null,
+     primary key (Id)
+);
+
+CREATE INDEX currentbackup_fileid on CurrentBackup (BackupId);
+CREATE INDEX currentbackup_idx on currentbackup (FilenameId, PathId);
+CREATE INDEX currentbackup_idx1 on currentbackup (FilenameId);
+CREATE INDEX currentbackup_idx2 on currentbackup (PathId);
+
+
+CREATE TEMPORARY TABLE batch (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
+
+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
+