1 Index: src/dird/backup.c
2 ===================================================================
3 --- src/dird/backup.c (révision 6374)
4 +++ src/dird/backup.c (copie de travail)
9 +#include "findlib/find.h"
11 /* Commands sent to File daemon */
12 static char backupcmd[] = "backup\n";
17 + * We are called here for each record that matches the above
18 + * SQL query -- that is for each file contained in the Catalog
19 + * that was not marked earlier. This means that the file in
20 + * question is a missing file (in the Catalog but not on Disk).
22 +static int missing_handler(void *ctx, int num_fields, char **row)
24 + JCR *jcr = (JCR *)ctx;
26 + if (job_canceled(jcr)) {
30 + /* TODO: return the list to the FD */
31 + if (num_fields == 2)
32 + Qmsg(jcr, M_INFO, 0, " %s%s\n", row[0]?row[0]:"", row[1]?row[1]:"");
34 + Qmsg(jcr, M_INFO, 0, " %s\n", row[0]?row[0]:"");
39 +bool accurate_check_file(JCR *jcr, FILE_DBR *fdbr, char *attr, char *Opts_Digest, int *do_Digest)
43 + struct stat statf; /* file stat */
44 + struct stat statc; /* catalog stat */
46 + int32_t LinkFIf, LinkFIc;
48 + decode_stat(attr, &statf, &LinkFIf); /* decode file stat packet */
49 + decode_stat(fdbr->LStat, &statc, &LinkFIc); /* decode catalog stat */
50 + *do_Digest = CRYPTO_DIGEST_NONE;
52 + for (p=Opts_Digest; *p; p++) {
53 + char ed1[30], ed2[30];
55 + case 'i': /* compare INODEs */
56 + if (statc.st_ino != statf.st_ino) {
57 + Jmsg(jcr, M_INFO, 0, _(" st_ino differ. Cat: %s File: %s\n"),
58 + edit_uint64((uint64_t)statc.st_ino, ed1),
59 + edit_uint64((uint64_t)statf.st_ino, ed2));
63 + case 'p': /* permissions bits */
64 + if (statc.st_mode != statf.st_mode) {
65 + Jmsg(jcr, M_INFO, 0, _(" st_mode differ. Cat: %x File: %x\n"),
66 + (uint32_t)statc.st_mode, (uint32_t)statf.st_mode);
70 + case 'n': /* number of links */
71 + if (statc.st_nlink != statf.st_nlink) {
72 + Jmsg(jcr, M_INFO, 0, _(" st_nlink differ. Cat: %d File: %d\n"),
73 + (uint32_t)statc.st_nlink, (uint32_t)statf.st_nlink);
77 + case 'u': /* user id */
78 + if (statc.st_uid != statf.st_uid) {
79 + Jmsg(jcr, M_INFO, 0, _(" st_uid differ. Cat: %u File: %u\n"),
80 + (uint32_t)statc.st_uid, (uint32_t)statf.st_uid);
84 + case 'g': /* group id */
85 + if (statc.st_gid != statf.st_gid) {
86 + Jmsg(jcr, M_INFO, 0, _(" st_gid differ. Cat: %u File: %u\n"),
87 + (uint32_t)statc.st_gid, (uint32_t)statf.st_gid);
91 + case 's': /* size */
92 + if (statc.st_size != statf.st_size) {
93 + Jmsg(jcr, M_INFO, 0, _(" st_size differ. Cat: %s File: %s\n"),
94 + edit_uint64((uint64_t)statc.st_size, ed1),
95 + edit_uint64((uint64_t)statf.st_size, ed2));
99 + case 'a': /* access time */
100 + if (statc.st_atime != statf.st_atime) {
101 + Jmsg(jcr, M_INFO, 0, _(" st_atime differs\n"));
106 + if (statc.st_mtime != statf.st_mtime) {
107 + Jmsg(jcr, M_INFO, 0, _(" st_mtime differs\n"));
111 + case 'c': /* ctime */
112 + if (statc.st_ctime != statf.st_ctime) {
113 + Jmsg(jcr, M_INFO, 0, _(" st_ctime differs\n"));
117 + case 'd': /* file size decrease */
118 + if (statc.st_size > statf.st_size) {
119 + Jmsg(jcr, M_INFO, 0, _(" st_size decrease. Cat: %s File: %s\n"),
120 + edit_uint64((uint64_t)statc.st_size, ed1),
121 + edit_uint64((uint64_t)statf.st_size, ed2));
125 + case '5': /* compare MD5 */
126 + Dmsg1(500, "set Do_MD5 for %s\n", jcr->fname);
127 + *do_Digest = CRYPTO_DIGEST_MD5;
129 + case '1': /* compare SHA1 */
130 + *do_Digest = CRYPTO_DIGEST_SHA1;
142 + * Accurate backup mode
143 + * 1. Receive the list of all files including those backed up to the Dir
144 + * 2. Dir computes files and deleted files.
145 + * 3. Dir sends list of additional files (new files) to backup, and list of files
148 + * Cleanup attributes (don't use atime, inode etc..)
149 + * Need to insert file and attributes to temp table ?
150 + * Batch compare files and attributes ?
152 + * If file have file_index=0, they are discarded by FD
154 + * TODO: send deleted list and new list to client
155 + * initialize currentlist and currentbackupid tables
156 + * tweak SD with file_index=-1
158 +bool accurate_compute_files(JCR *jcr)
163 + char buf[MAXSTRING];
164 + char ed1[50], ed2[50];
165 + POOLMEM *fname = get_pool_memory(PM_MESSAGE);
166 + int do_Digest = CRYPTO_DIGEST_NONE;
167 + int32_t file_index = 0;
168 + JobId_t JobId=0; /* TODO: compute the job key in new table */
169 + JobId_t backupid=0;
171 + memset(&fdbr, 0, sizeof(FILE_DBR));
172 + fd = jcr->file_bsock;
173 + fdbr.JobId = JobId;
174 + jcr->FileIndex = 0;
176 + if (/*jcr->accurate == false ||*/ jcr->JobLevel == L_FULL) {
180 + backupid = db_find_backupid(jcr, jcr->db, &jcr->jr);
182 + Jmsg(jcr, M_ERROR, 0, _("Can't use Accurate mode ERR=Can't find BackupId\n"));
185 + db_accurate_create_backup_table(jcr, jcr->db, jcr->JobId);
186 + Dmsg0(1, "bdird: waiting to receive file attributes\n");
188 + * Get Attributes and Signature from File daemon
192 + * Options or Digest (MD5/SHA1)
197 + while ((n=bget_dirmsg(fd)) >= 0 && !job_canceled(jcr)) {
199 + char *attr, *p, *fn;
200 + char Opts_Digest[MAXSTRING]; /* Verify Opts or MD5/SHA1 digest */
202 + if (job_canceled(jcr)) {
205 + fname = check_pool_memory_size(fname, fd->msglen);
206 + jcr->fname = check_pool_memory_size(jcr->fname, fd->msglen);
207 + Dmsg1(1, "Atts+Digest=%s\n", fd->msg);
208 + if ((len = sscanf(fd->msg, "%ld %d %100s", &file_index, &stream,
210 + Jmsg3(jcr, M_FATAL, 0, _("bird<filed: bad attributes, expected 3 fields got %d\n"
211 +" mslen=%d msg=%s\n"), len, fd->msglen, fd->msg);
215 + * We read the Options or Signature into fname
216 + * to prevent overrun, now copy it to proper location.
218 + bstrncpy(Opts_Digest, fname, sizeof(Opts_Digest));
220 + skip_nonspaces(&p); /* skip FileIndex */
222 + skip_nonspaces(&p); /* skip Stream */
224 + skip_nonspaces(&p); /* skip Opts_Digest */
225 + p++; /* skip space */
228 + *fn++ = *p++; /* copy filename */
230 + *fn = *p++; /* term filename and point to attribs */
233 + * Got attributes stream, decode it
235 + if (stream == STREAM_UNIX_ATTRIBUTES || stream == STREAM_UNIX_ATTRIBUTES_EX) {
237 + Dmsg2(400, "file_index=%d attr=%s\n", file_index, attr);
239 + jcr->FileIndex = file_index; /* remember attribute file_index */
240 + do_Digest = CRYPTO_DIGEST_NONE;
241 + pm_strcpy(jcr->fname, fname); /* move filename into JCR */
245 + * Find equivalent record in the database
248 + if (db_accurate_get_file_attributes_record(jcr, jcr->db, jcr->fname,
251 + Dmsg2(1, "get_file ok fname=%s fileid=%i\n", jcr->fname, fdbr.FileId);
253 + if (file_index != 0) {
254 + changed = accurate_check_file(jcr, &fdbr, attr, Opts_Digest, &do_Digest);
255 + Dmsg1(1, "check_file changed=%i\n", changed);
257 + if (changed == true) {
258 + db_accurate_mark_file_for_backup(jcr, jcr->db, jcr->fname, jcr->JobId);
259 + db_accurate_delete_file_record(jcr, jcr->db, fdbr.FileId,
264 + if (file_index == 0 || changed == false) {
265 + Dmsg1(1, "mark_file fileid=%i\n", fdbr.FileId);
266 + db_accurate_mark_file_record(jcr, jcr->db, backupid,
267 + fdbr.FileId, jcr->JobId);
270 + } else if (file_index == 0) {
271 + Dmsg1(1, "mark_for_backup fname=%s\n", jcr->fname);
272 + db_accurate_mark_file_for_backup(jcr, jcr->db, jcr->fname, jcr->JobId);
277 + * Got Digest Signature from Storage daemon
278 + * It came across in the Opts_Digest field.
280 + } else if (crypto_digest_stream_type(stream) != CRYPTO_DIGEST_NONE) {
281 + Dmsg2(400, "stream=Digest inx=%d Digest=%s\n", file_index, Opts_Digest);
283 + * When ever we get a digest it MUST have been
284 + * preceded by an attributes record, which sets attr_file_index
286 + if (jcr->FileIndex != (uint32_t)file_index) {
287 + Jmsg2(jcr, M_FATAL, 0, _("MD5/SHA1 index %d not same as attributes %d\n"),
288 + file_index, jcr->FileIndex);
291 + if (do_Digest != CRYPTO_DIGEST_NONE) {
292 + db_escape_string(jcr, jcr->db, buf, Opts_Digest, strlen(Opts_Digest));
293 + if (strcmp(buf, fdbr.Digest) != 0) {
294 + if (debug_level >= 10) {
295 + Jmsg(jcr, M_INFO, 0, _(" %d not same. File=%s Cat=%s\n"),
296 + stream, buf, fdbr.Digest);
298 + Jmsg(jcr, M_INFO, 0, _(" %d differs.\n"),
301 + //stat = JS_Differences;
303 + do_Digest = CRYPTO_DIGEST_NONE;
306 +// jcr->JobFiles = file_index;
308 + if (is_bnet_error(fd)) {
310 + Jmsg2(jcr, M_FATAL, 0, _("bdird<filed: bad attributes from filed n=%d : %s\n"),
311 + n, be.bstrerror());
315 + /* Now find all the files that are missing -- i.e. all files in
316 + * the database where the MarkId != current JobId
319 + bsnprintf(buf, sizeof(buf),
320 + "SELECT Path.Path,Filename.Name "
321 + "FROM CurrentFile "
322 + "JOIN File USING (FileId) "
323 + "JOIN Path USING (PathId) "
324 + "JOIN Filename USING (FilenameId) "
325 + "WHERE CurrentFile.BackupId=%s "
326 + "AND CurrentFile.MarkId!=%s ",
327 + edit_uint64(backupid, ed1), edit_uint64(jcr->JobId, ed2));
328 + /* missing_handler is called for each file found */
329 + Dmsg1(1, "display deleted files cmd=%s\n", buf);
330 + db_sql_query(jcr->db, buf, missing_handler, (void *)jcr);
332 + bsnprintf(buf, sizeof(buf),
333 + "SELECT Name FROM ToBackup%s",
334 + edit_uint64(jcr->JobId, ed2));
335 + /* missing_handler is called for each file found */
336 + Dmsg1(1, "display files to backup cmd=%s\n", buf);
337 + db_sql_query(jcr->db, buf, missing_handler, (void *)jcr);
339 + free_pool_memory(fname);
344 + db_accurate_drop_backup_table(jcr, jcr->db, jcr->JobId);
349 * Do a backup of the specified FileSet
351 * Returns: false on failure
357 + * If backup is in accurate mode, FD will send the list of
358 + * all files. We have to store it, and compute witch files
359 + * have been deleted and witch files have to be backuped.
361 + accurate_compute_files(jcr);
363 /* Pickup Job termination data */
364 stat = wait_for_job_termination(jcr);
365 db_write_batch_file_records(jcr); /* used by bulk batch file insert */
366 Index: src/dird/inc_conf.c
367 ===================================================================
368 --- src/dird/inc_conf.c (révision 6374)
369 +++ src/dird/inc_conf.c (copie de travail)
371 * Items that are valid in an Options resource
373 static RES_ITEM options_items[] = {
374 + {"accurate", store_opts, {0}, 0, 0, 0},
375 {"compression", store_opts, {0}, 0, 0, 0},
376 {"signature", store_opts, {0}, 0, 0, 0},
377 {"verify", store_opts, {0}, 0, 0, 0},
389 * options given above.
391 static struct s_kw FS_option_kw[] = {
392 + {"accurate", INC_KW_ACCURATE},
393 {"compression", INC_KW_COMPRESSION},
394 {"signature", INC_KW_DIGEST},
395 {"encryption", INC_KW_ENCRYPTION},
397 {"no", INC_KW_ENHANCEDWILD, "0"},
398 {"yes", INC_KW_CHKCHANGES, "c"},
399 {"no", INC_KW_CHKCHANGES, "0"},
400 + {"yes", INC_KW_ACCURATE, "C"},
401 + {"no", INC_KW_ACCURATE, "0"},
405 Index: src/dird/dird_conf.c
406 ===================================================================
407 --- src/dird/dird_conf.c (révision 6374)
408 +++ src/dird/dird_conf.c (copie de travail)
410 {"selectionpattern", store_str, ITEM(res_job.selection_pattern), 0, 0, 0},
411 {"runscript", store_runscript, ITEM(res_job.RunScripts), 0, ITEM_NO_EQUALS, 0},
412 {"selectiontype", store_migtype, ITEM(res_job.selection_type), 0, 0, 0},
413 + {"accuratebackup", store_bool, ITEM(res_job.accurate), 0,0,0},
414 {NULL, NULL, {0}, 0, 0, 0}
418 if (res->res_job.spool_size) {
419 sendit(sock, _(" SpoolSize=%s\n"), edit_uint64(res->res_job.spool_size, ed1));
421 + if (res->res_job.JobType == JT_BACKUP) {
422 + sendit(sock, _(" Accurate=%d\n"), res->res_job.accurate);
424 if (res->res_job.JobType == JT_MIGRATE) {
425 sendit(sock, _(" SelectionType=%d\n"), res->res_job.selection_type);
427 Index: src/dird/dird_conf.h
428 ===================================================================
429 --- src/dird/dird_conf.h (révision 6374)
430 +++ src/dird/dird_conf.h (copie de travail)
432 bool write_part_after_job; /* Set to write part after job in SD */
433 bool enabled; /* Set if job enabled */
434 bool OptimizeJobScheduling; /* Set if we should optimize Job scheduling */
435 + bool accurate; /* Set if it is an accurate backup job */
437 MSGS *messages; /* How and where to send messages */
438 SCHED *schedule; /* When -- Automatic schedule */
439 Index: src/filed/backup.c
440 ===================================================================
441 --- src/filed/backup.c (révision 6374)
442 +++ src/filed/backup.c (copie de travail)
444 static bool crypto_session_send(JCR *jcr, BSOCK *sd);
447 + * Called by save_file when accept/discard file for backup
449 + * TODO: we could add MD5/SHAX digest, but we have to compute it
452 +static bool accurate_add_file(JCR *jcr, FF_PKT *ff_pkt, char *stats)
455 + char attribs[MAXSTRING];
456 + uint32_t file_index=jcr->JobFiles;
457 + BSOCK *dir = jcr->dir_bsock;
460 + if (jcr->accurate == false || jcr->JobLevel == L_FULL) {
464 + if (!stats) { /* TODO: don't always compute attribute */
466 + encode_stat(attribs, ff_pkt, 0);
470 + switch (ff_pkt->type) {
471 + case FT_LNKSAVED: /* Hard linked, file already saved */
473 + stat = dir->fsend("%d %d %s %s%c%s%c%s%c", file_index,
474 + STREAM_UNIX_ATTRIBUTES, ff_pkt->VerifyOpts, ff_pkt->fname,
475 + 0, a, 0, ff_pkt->link, 0);
483 + stat = dir->fsend("%d %d %s %s%c%s%c%c", file_index,
484 + STREAM_UNIX_ATTRIBUTES, ff_pkt->VerifyOpts, ff_pkt->fname,
492 + stat = dir->fsend("%d %d %s %s%c%s%c%c", file_index,
493 + STREAM_UNIX_ATTRIBUTES, ff_pkt->VerifyOpts, ff_pkt->link,
497 + Dmsg2(1, _("Fname=%s Type=%i\n"), ff_pkt->fname, ff_pkt->type);
502 + Jmsg(jcr, M_FATAL, 0, _("Network error in send to Director: ERR=%s\n"), bnet_strerror(dir));
509 +/* build a fileset with new files from director */
510 +static bool accurate_get_new_and_deleted_file_list(JCR *jcr)
512 + if (jcr->accurate == false || job_canceled(jcr)) {
518 +/* send deleted file list to stored */
519 +static bool accurate_send_deleted_list(JCR *jcr)
521 + if (jcr->accurate == false || job_canceled(jcr)) {
527 +static bool accurate_send_file_list(JCR *jcr)
529 + if (jcr->accurate == false || job_canceled(jcr)) {
532 + Dmsg0(1, "Sending BNET_EOD\n");
533 + jcr->dir_bsock->signal(BNET_EOD); /* end of sending data */
539 * Find all the requested files and send them
540 * to the Storage daemon.
545 // TODO landonf: Allow user to specify encryption algorithm
546 + if (jcr->JobLevel != L_FULL) {
547 + jcr->accurate=true; /* TODO: remove that */
550 sd = jcr->store_bsock;
553 ok = false; /* error */
554 set_jcr_job_status(jcr, JS_ErrorTerminated);
556 + Dmsg1(1, "jcr->accurate == %i\n", jcr->accurate);
557 + /* start accurate stuffs */
558 + if (jcr->accurate) {
559 + /* TODO: test job_canceled() */
560 + accurate_send_file_list(jcr); /* send all files to DIR */
561 + accurate_get_new_and_deleted_file_list(jcr); /* get a new incr fileset from DIR */
562 +// set_find_options((FF_PKT *)jcr->ff, 0, 0); /* we backup all that director wants */
563 +// if (!find_files(jcr, (FF_PKT *)jcr->ff, save_file, (void *)jcr)) {
564 +// ok = false; /* error */
565 +// set_jcr_job_status(jcr, JS_ErrorTerminated);
567 +// accurate_send_file_list(jcr); /* send all new files to DIR */
568 + accurate_send_deleted_list(jcr); /* send deleted list to SD */
571 free_pool_memory(jcr->acl_text);
576 Jmsg(jcr, M_SKIPPED, 1, _(" Unchanged file skipped: %s\n"), ff_pkt->fname);
577 + accurate_add_file(jcr, ff_pkt, NULL); /* list skipped files */
580 Jmsg(jcr, M_NOTSAVED, 0, _(" Archive file not saved: %s\n"), ff_pkt->fname);
581 + accurate_add_file(jcr, ff_pkt, NULL); /* list skipped files */
585 @@ -1111,6 +1222,9 @@
587 unstrip_path(ff_pkt);
589 + /* list backuped files */
590 + accurate_add_file(jcr, ff_pkt, attribs);
592 Dmsg2(300, ">stored: attr len=%d: %s\n", sd->msglen, sd->msg);
594 Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
595 Index: src/filed/job.c
596 ===================================================================
597 --- src/filed/job.c (révision 6374)
598 +++ src/filed/job.c (copie de travail)
599 @@ -1087,6 +1087,9 @@
601 fo->flags |= FO_CHKCHANGES;
604 + fo->flags |= FO_ACCURATE;
607 Emsg1(M_ERROR, 0, _("Unknown include/exclude option: %c\n"), *p);
609 Index: src/cats/sql_update.c
610 ===================================================================
611 --- src/cats/sql_update.c (révision 6374)
612 +++ src/cats/sql_update.c (copie de travail)
617 +int db_accurate_delete_file_record(JCR *jcr, B_DB *mdb, FileId_t FileId, JobId_t BackupId)
620 + char ed1[50], ed2[50];
622 + Mmsg(mdb->cmd, "DELETE FROM CurrentFile WHERE FileId=%s AND BackupId=%s",
623 + edit_int64(FileId, ed1), edit_int64(BackupId, ed2));
624 + stat = QUERY_DB(jcr, mdb, mdb->cmd);
629 +int db_accurate_mark_file_for_backup(JCR *jcr, B_DB *mdb, char *fname, JobId_t JobId)
632 + int len=strlen(fname);
635 + /* TODO: mdb->esc_xxx are already ok but it's more smart to recompute it */
636 +// mdb->esc_name = check_pool_memory_size(mdb->esc_name, 2*len+2);
637 +// mdb->esc_name = db_escape_string(jcr, mdb, mdb->esc_name, fname, len);
638 + Mmsg(mdb->cmd, "INSERT INTO ToBackup%s (name) VALUES ('%s%s')", edit_int64(JobId, ed1), mdb->esc_path, mdb->esc_name);
639 + stat = INSERT_DB(jcr, mdb, mdb->cmd);
644 +int db_accurate_create_backup_table(JCR *jcr, B_DB *mdb, JobId_t JobId)
649 + Mmsg(mdb->cmd, "CREATE TABLE ToBackup%s (name text)", edit_int64(JobId, ed1));
650 +// Mmsg(mdb->cmd, "CREATE TEMPORARY TABLE ToBackup%s (name text)", edit_int64(JobId, ed1));
651 + stat = QUERY_DB(jcr, mdb, mdb->cmd);
656 +int db_accurate_drop_backup_table(JCR *jcr, B_DB *mdb, JobId_t JobId)
661 +// Mmsg(mdb->cmd, "DROP TABLE ToBackup%s", edit_int64(JobId, ed1));
662 +// stat = QUERY_DB(jcr, mdb, mdb->cmd);
668 +/* Mark the file record as being visited during database
669 + * accurate compare. Stuff JobId into the MarkId field
671 +int db_accurate_mark_file_record(JCR *jcr, B_DB *mdb, JobId_t BackupId, FileId_t FileId, JobId_t JobId)
674 + char ed1[50], ed2[50], ed3[50];
677 + Mmsg(mdb->cmd, "UPDATE CurrentFile SET MarkId=%s WHERE FileId=%s AND BackupId=%s",
678 + edit_int64(JobId, ed1), edit_int64(FileId, ed2), edit_int64(BackupId, ed3));
679 + stat = QUERY_DB(jcr, mdb, mdb->cmd);
680 + if (!stat || sql_affected_rows(mdb) != 1) {
688 * Update the Job record at start of Job
690 Index: src/cats/make_postgresql_tables.in
691 ===================================================================
692 --- src/cats/make_postgresql_tables.in (révision 6374)
693 +++ src/cats/make_postgresql_tables.in (copie de travail)
695 CREATE INDEX file_jobid_idx on file (jobid);
696 CREATE INDEX file_fp_idx on file (filenameid, pathid);
698 +CREATE TABLE CurrentBackupId
700 + BackupId serial not null,
701 + ClientId integer not null,
702 + JobName text not null,
703 + FileSetId integer not null,
704 + primary key (BackupId)
707 +-- Serait bien de prendre la meme table pour
708 +-- les File et le CurrentBackup...
709 +-- Mais y'a des problemes pour les prunes
711 +CREATE TABLE CurrentFile
713 + FileId integer not null,
714 + BackupId integer not null,
715 + FullMark char(1) default 0,
716 + MarkId integer default 0,
717 + primary key (FileId)
720 +CREATE INDEX currentfile_fileid on CurrentFile (BackupId);
722 +-- CREATE TEMPORARY TABLE batch (fileindex int,
729 +-- -- On batch insert dans la table temporaire
731 +-- il faut trouver les fichiers manquant
732 +-- INSERT des nouveaux, UPDATE des anciens, SELECT pour trouver les deletes
735 +-- il faut trouver les fichiers modifies
736 +-- Le champs LStat n'est plus le meme
738 +-- FROM CurrentBackup,
739 +-- batch JOIN Path USING (Path) JOIN Filename USING (Name)
740 +-- WHERE Path.PathId = CurrentBackup.PathId
741 +-- AND Filename.FilenameId = CurrentBackup.FilenameId
742 +-- AND CurrentBackup.LStat != batch.LStat
744 +-- il faut mettre a jour la liste des fichiers
752 -- Possibly add one or more of the following indexes
753 -- if your Verifies are too slow.
754 Index: src/cats/protos.h
755 ===================================================================
756 --- src/cats/protos.h (révision 6374)
757 +++ src/cats/protos.h (copie de travail)
760 bool db_find_job_start_time(JCR *jcr, B_DB *mdb, JOB_DBR *jr, POOLMEM **stime);
761 bool db_find_last_jobid(JCR *jcr, B_DB *mdb, const char *Name, JOB_DBR *jr);
762 +JobId_t db_find_backupid(JCR *jcr, B_DB *mdb, JOB_DBR *jr);
763 int db_find_next_volume(JCR *jcr, B_DB *mdb, int index, bool InChanger, MEDIA_DBR *mr);
764 bool db_find_failed_job_since(JCR *jcr, B_DB *mdb, JOB_DBR *jr, POOLMEM *stime, int &JobLevel);
767 +int db_accurate_get_file_attributes_record(JCR *jcr, B_DB *mdb, char *fname, JobId_t backupid, FILE_DBR *fdbr);
768 bool db_get_pool_record(JCR *jcr, B_DB *db, POOL_DBR *pdbr);
769 int db_get_client_record(JCR *jcr, B_DB *mdb, CLIENT_DBR *cr);
770 bool db_get_job_record(JCR *jcr, B_DB *mdb, JOB_DBR *jr);
772 int db_update_counter_record(JCR *jcr, B_DB *mdb, COUNTER_DBR *cr);
773 int db_add_digest_to_file_record(JCR *jcr, B_DB *mdb, FileId_t FileId, char *digest, int type);
774 int db_mark_file_record(JCR *jcr, B_DB *mdb, FileId_t FileId, JobId_t JobId);
775 +int db_accurate_mark_file_for_backup(JCR *jcr, B_DB *mdb, char *fname, FileId_t JobId);
776 +int db_accurate_mark_file_record(JCR *jcr, B_DB *mdb, JobId_t BackupId, FileId_t FileId, JobId_t JobId);
777 +int db_accurate_drop_backup_table(JCR *jcr, B_DB *mdb, JobId_t JobId);
778 +int db_accurate_create_backup_table(JCR *jcr, B_DB *mdb, JobId_t JobId);
779 +int db_accurate_delete_file_record(JCR *jcr, B_DB *mdb, FileId_t FileId, JobId_t BackupId);
780 void db_make_inchanger_unique(JCR *jcr, B_DB *mdb, MEDIA_DBR *mr);
782 #endif /* __SQL_PROTOS_H */
783 Index: src/cats/sql_find.c
784 ===================================================================
785 --- src/cats/sql_find.c (révision 6374)
786 +++ src/cats/sql_find.c (copie de travail)
792 + * Find BackupId of last job that ran. E.g. for
794 + * Returns: Last backuip
798 +db_find_backupid(JCR *jcr, B_DB *mdb, JOB_DBR *jr)
801 + char ed1[50],ed2[50];
802 + JobId_t backupid=0;
804 + /* Find backupid */
806 + Dmsg2(100, "JobLevel=%d JobType=%d\n", jcr->JobLevel, jcr->JobType);
808 +"SELECT BackupId FROM CurrentBackupId WHERE JobName='%s' AND "
809 +"ClientId=%s AND FileSetId=%s ORDER BY BackupId DESC LIMIT 1",
811 + edit_int64(jr->ClientId, ed1),
812 + edit_int64(jr->FileSetId, ed2));
814 + Dmsg1(100, "Query: %s\n", mdb->cmd);
815 + if (!QUERY_DB(jcr, mdb, mdb->cmd)) {
819 + if ((row = sql_fetch_row(mdb)) == NULL) {
820 + Mmsg1(&mdb->errmsg, _("No Job found for: %s.\n"), mdb->cmd);
821 + sql_free_result(mdb);
826 + backupid = str_to_int64(row[0]);
827 + sql_free_result(mdb);
829 + if (backupid <= 0) {
830 + Mmsg1(&mdb->errmsg, _("No Job found for: %s\n"), mdb->cmd);
841 * Find JobId of last job that ran. E.g. for
842 * VERIFY_CATALOG we want the JobId of the last INIT.
843 Index: src/cats/sql_create.c
844 ===================================================================
845 --- src/cats/sql_create.c (révision 6374)
846 +++ src/cats/sql_create.c (copie de travail)
851 +bool db_accurate_insert(JCR *jcr, B_DB *mdb, bool saved, const char *fname, struct stat *stat)
854 + split_path_and_file(jcr, mdb, fname);
855 + /* make like in Verify code */
860 * Create File record in B_DB
862 Index: src/cats/sql_get.c
863 ===================================================================
864 --- src/cats/sql_get.c (révision 6374)
865 +++ src/cats/sql_get.c (copie de travail)
868 * Returns: 0 on failure
869 * 1 on success with the File record in FILE_DBR
871 + * TODO: optimize this with only one query
873 int db_get_file_attributes_record(JCR *jcr, B_DB *mdb, char *fname, JOB_DBR *jr, FILE_DBR *fdbr)
880 + * Given a full filename (with path), look up the File record
881 + * (with attributes) in the database.
883 + * Returns: 0 on failure
884 + * 1 on success with the File record in FILE_DBR
886 +int db_accurate_get_file_attributes_record(JCR *jcr, B_DB *mdb, char *fname, JobId_t backupid, FILE_DBR *fdbr)
893 + split_path_and_file(jcr, mdb, fname);
895 + mdb->esc_name = check_pool_memory_size(mdb->esc_name, 2*mdb->fnl+2);
896 + db_escape_string(jcr, mdb, mdb->esc_name, mdb->fname, mdb->fnl);
898 + mdb->esc_path = check_pool_memory_size(mdb->esc_path, 2*mdb->pnl+2);
899 + db_escape_string(jcr, mdb, mdb->esc_path, mdb->path, mdb->pnl);
902 +"SELECT FileId, LStat, MD5, FilenameId, PathId, FileIndex, CurrentFile.MarkId, JobId "
903 + "FROM File JOIN CurrentFile USING (FileId) "
904 + "JOIN Filename USING (FilenameId) "
905 + "JOIN Path USING (PathId) "
906 + "WHERE Path.Path='%s' "
907 + "AND Filename.Name='%s' "
908 + "AND BackupId=%s ",
911 + edit_int64(backupid, ed1));
913 + Dmsg1(100,"get_file %s\n", mdb->cmd);
915 + if (QUERY_DB(jcr, mdb, mdb->cmd)) {
917 + mdb->num_rows = sql_num_rows(mdb);
918 + if (mdb->num_rows == 1) {
919 + if ((row = sql_fetch_row(mdb)) == NULL) {
920 + Mmsg1(mdb->errmsg, _("error fetching row: %s\n"), sql_strerror(mdb));
922 + fdbr->FileId = str_to_int64(row[0]);
923 + bstrncpy(fdbr->LStat, row[1], sizeof(fdbr->LStat));
924 + bstrncpy(fdbr->Digest, row[2], sizeof(fdbr->Digest));
925 + fdbr->FilenameId = str_to_int64(row[3]);
926 + fdbr->PathId = str_to_int64(row[4]);
927 + fdbr->FileIndex = str_to_int64(row[5]);
928 + fdbr->MarkId = str_to_int64(row[6]);
929 + fdbr->JobId = str_to_int64(row[7]);
932 + } else if (mdb->num_rows > 1) {
933 + Mmsg2(mdb->errmsg, _("Get DB File record %s failed num=%i\n"),fname,mdb->num_rows);
934 + Jmsg(jcr, M_WARNING, 0, "%s", mdb->errmsg);
936 + sql_free_result(mdb);
938 + Mmsg(mdb->errmsg, _("File record: %s not found in Catalog for BackupId=%s.\n"), fname, ed1);
948 * Returns: 0 on failure
950 ===================================================================
951 --- src/jcr.h (révision 6374)
952 +++ src/jcr.h (copie de travail)
954 B_DB *db_batch; /* database pointer for batch insert */
955 ATTR_DBR *ar; /* DB attribute record */
956 guid_list *id_list; /* User/group id to name list */
957 + bool accurate; /* true if job is accurate */
959 void *plugin_ctx_list; /* list of contexts for plugins */
960 void *plugin_ctx; /* current plugin context */
961 Index: src/findlib/find.h
962 ===================================================================
963 --- src/findlib/find.h (révision 6374)
964 +++ src/findlib/find.h (copie de travail)
966 #define FO_ENHANCEDWILD (1<<23) /* Enhanced wild card processing */
967 #define FO_CHKCHANGES (1<<24) /* Check if file have been modified during backup */
968 #define FO_STRIPPATH (1<<25) /* Check for stripping path */
969 +#define FO_ACCURATE (1<<26) /* Accurate mode */
971 struct s_included_file {
972 struct s_included_file *next;