1 Index: src/dird/backup.c
2 ===================================================================
3 --- src/dird/backup.c (révision 6373)
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 + Qmsg(jcr, M_INFO, 0, " %s%s\n", row[0]?row[0]:"", row[1]?row[1]:"");
36 + * Accurate backup mode
37 + * 1. Receive the list of all files including those backed up to the Dir
38 + * 2. Dir computes files and deleted files.
39 + * 3. Dir sends list of additional files (new files) to backup, and list of files
42 + * Cleanup attributes (don't use atime, inode etc..)
43 + * Need to insert file and attributes to temp table
44 + * Batch compare files and attributes
46 + * If file have file_index=0, they are discarded by FD
49 +bool accurate_compute_files(JCR *jcr)
54 + struct stat statf; /* file stat */
55 + struct stat statc; /* catalog stat */
56 + int stat = JS_Terminated;
57 + char buf[MAXSTRING];
58 + char ed1[50], ed2[50];
59 + POOLMEM *fname = get_pool_memory(PM_MESSAGE);
60 + int do_Digest = CRYPTO_DIGEST_NONE;
61 + int32_t file_index = 0;
62 + JobId_t JobId=0; /* TODO: compute the job key in new table */
65 + memset(&fdbr, 0, sizeof(FILE_DBR));
66 + fd = jcr->file_bsock;
70 + if (/*jcr->accurate == false ||*/ jcr->JobLevel == L_FULL) {
74 + backupid = db_find_backupid(jcr, jcr->db, &jcr->jr);
76 + Jmsg(jcr, M_ERROR, 0, _("Can't use Accurate mode ERR=Can't find BackupId\n"));
80 + Dmsg0(1, "bdird: waiting to receive file attributes\n");
82 + * Get Attributes and Signature from File daemon
86 + * Options or Digest (MD5/SHA1)
91 + while ((n=bget_dirmsg(fd)) >= 0 && !job_canceled(jcr)) {
93 + char *attr, *p, *fn;
94 + char Opts_Digest[MAXSTRING]; /* Verify Opts or MD5/SHA1 digest */
96 + if (job_canceled(jcr)) {
99 + fname = check_pool_memory_size(fname, fd->msglen);
100 + jcr->fname = check_pool_memory_size(jcr->fname, fd->msglen);
101 + Dmsg1(1, "Atts+Digest=%s\n", fd->msg);
102 + if ((len = sscanf(fd->msg, "%ld %d %100s", &file_index, &stream,
104 + Jmsg3(jcr, M_FATAL, 0, _("bird<filed: bad attributes, expected 3 fields got %d\n"
105 +" mslen=%d msg=%s\n"), len, fd->msglen, fd->msg);
109 + * We read the Options or Signature into fname
110 + * to prevent overrun, now copy it to proper location.
112 + bstrncpy(Opts_Digest, fname, sizeof(Opts_Digest));
114 + skip_nonspaces(&p); /* skip FileIndex */
116 + skip_nonspaces(&p); /* skip Stream */
118 + skip_nonspaces(&p); /* skip Opts_Digest */
119 + p++; /* skip space */
122 + *fn++ = *p++; /* copy filename */
124 + *fn = *p++; /* term filename and point to attribs */
127 + * Got attributes stream, decode it
129 + if (stream == STREAM_UNIX_ATTRIBUTES || stream == STREAM_UNIX_ATTRIBUTES_EX) {
130 + int32_t LinkFIf, LinkFIc;
131 + Dmsg2(400, "file_index=%d attr=%s\n", file_index, attr);
133 + jcr->FileIndex = file_index; /* remember attribute file_index */
134 + decode_stat(attr, &statf, &LinkFIf); /* decode file stat packet */
135 + do_Digest = CRYPTO_DIGEST_NONE;
136 + pm_strcpy(jcr->fname, fname); /* move filename into JCR */
138 + Dmsg3(040, "dird<filed: stream=%d %s %s\n", stream, jcr->fname, attr);
141 + * Find equivalent record in the database
144 + /* If file_index==0, file is not saved by fd, check them */
145 + if (!db_accurate_get_file_attributes_record(jcr, jcr->db, jcr->fname, backupid, &fdbr)) {
146 + Jmsg(jcr, M_INFO, 0, _("New file: %s\n"), jcr->fname);
147 + Dmsg1(1, _("File not in catalog: %s\n"), jcr->fname);
150 + Dmsg1(1, _("File in catalog: %s\n"), jcr->fname);
152 + * mark file record as visited by stuffing the
153 + * current JobId, which is unique, into the MarkId field.
155 + db_mark_file_record(jcr, jcr->db, fdbr.FileId, jcr->JobId);
158 + Dmsg3(400, "Found %s in catalog. inx=%d Opts=%s\n", jcr->fname,
159 + file_index, Opts_Digest);
160 + decode_stat(fdbr.LStat, &statc, &LinkFIc); /* decode catalog stat */
162 + // TODO: for each JS_Differences, send it to FD for backup
164 + * Loop over options supplied by user and verify the
165 + * fields he requests.
167 + stat = JS_Terminated; /* TODO: track changes */
168 + for (p=Opts_Digest; *p; p++) {
169 + char ed1[30], ed2[30];
171 + case 'i': /* compare INODEs */
172 + if (statc.st_ino != statf.st_ino) {
173 + Jmsg(jcr, M_INFO, 0, _(" st_ino differ. Cat: %s File: %s\n"),
174 + edit_uint64((uint64_t)statc.st_ino, ed1),
175 + edit_uint64((uint64_t)statf.st_ino, ed2));
176 + stat = JS_Differences;
179 + case 'p': /* permissions bits */
180 + if (statc.st_mode != statf.st_mode) {
181 + Jmsg(jcr, M_INFO, 0, _(" st_mode differ. Cat: %x File: %x\n"),
182 + (uint32_t)statc.st_mode, (uint32_t)statf.st_mode);
183 + stat = JS_Differences;
186 + case 'n': /* number of links */
187 + if (statc.st_nlink != statf.st_nlink) {
188 + Jmsg(jcr, M_INFO, 0, _(" st_nlink differ. Cat: %d File: %d\n"),
189 + (uint32_t)statc.st_nlink, (uint32_t)statf.st_nlink);
190 + stat = JS_Differences;
193 + case 'u': /* user id */
194 + if (statc.st_uid != statf.st_uid) {
195 + Jmsg(jcr, M_INFO, 0, _(" st_uid differ. Cat: %u File: %u\n"),
196 + (uint32_t)statc.st_uid, (uint32_t)statf.st_uid);
197 + stat = JS_Differences;
200 + case 'g': /* group id */
201 + if (statc.st_gid != statf.st_gid) {
202 + Jmsg(jcr, M_INFO, 0, _(" st_gid differ. Cat: %u File: %u\n"),
203 + (uint32_t)statc.st_gid, (uint32_t)statf.st_gid);
204 + stat = JS_Differences;
207 + case 's': /* size */
208 + if (statc.st_size != statf.st_size) {
209 + Jmsg(jcr, M_INFO, 0, _(" st_size differ. Cat: %s File: %s\n"),
210 + edit_uint64((uint64_t)statc.st_size, ed1),
211 + edit_uint64((uint64_t)statf.st_size, ed2));
212 + stat = JS_Differences;
215 + case 'a': /* access time */
216 + if (statc.st_atime != statf.st_atime) {
217 + Jmsg(jcr, M_INFO, 0, _(" st_atime differs\n"));
218 + stat = JS_Differences;
222 + if (statc.st_mtime != statf.st_mtime) {
223 + Jmsg(jcr, M_INFO, 0, _(" st_mtime differs\n"));
224 + stat = JS_Differences;
227 + case 'c': /* ctime */
228 + if (statc.st_ctime != statf.st_ctime) {
229 + Jmsg(jcr, M_INFO, 0, _(" st_ctime differs\n"));
230 + stat = JS_Differences;
233 + case 'd': /* file size decrease */
234 + if (statc.st_size > statf.st_size) {
235 + Jmsg(jcr, M_INFO, 0, _(" st_size decrease. Cat: %s File: %s\n"),
236 + edit_uint64((uint64_t)statc.st_size, ed1),
237 + edit_uint64((uint64_t)statf.st_size, ed2));
238 + stat = JS_Differences;
241 + case '5': /* compare MD5 */
242 + Dmsg1(500, "set Do_MD5 for %s\n", jcr->fname);
243 + do_Digest = CRYPTO_DIGEST_MD5;
245 + case '1': /* compare SHA1 */
246 + do_Digest = CRYPTO_DIGEST_SHA1;
254 + if (stat == JS_Differences) {
255 + Jmsg(jcr, M_INFO, 0, _(" fname=%s\n"), jcr->fname);
259 + * Got Digest Signature from Storage daemon
260 + * It came across in the Opts_Digest field.
262 + } else if (crypto_digest_stream_type(stream) != CRYPTO_DIGEST_NONE) {
263 + Dmsg2(400, "stream=Digest inx=%d Digest=%s\n", file_index, Opts_Digest);
265 + * When ever we get a digest it MUST have been
266 + * preceded by an attributes record, which sets attr_file_index
268 + if (jcr->FileIndex != (uint32_t)file_index) {
269 + Jmsg2(jcr, M_FATAL, 0, _("MD5/SHA1 index %d not same as attributes %d\n"),
270 + file_index, jcr->FileIndex);
273 + if (do_Digest != CRYPTO_DIGEST_NONE) {
274 + db_escape_string(jcr, jcr->db, buf, Opts_Digest, strlen(Opts_Digest));
275 + if (strcmp(buf, fdbr.Digest) != 0) {
276 + if (debug_level >= 10) {
277 + Jmsg(jcr, M_INFO, 0, _(" %d not same. File=%s Cat=%s\n"),
278 + stream, buf, fdbr.Digest);
280 + Jmsg(jcr, M_INFO, 0, _(" %d differs.\n"),
283 + stat = JS_Differences;
285 + do_Digest = CRYPTO_DIGEST_NONE;
288 +// jcr->JobFiles = file_index;
290 + if (is_bnet_error(fd)) {
292 + Jmsg2(jcr, M_FATAL, 0, _("bdird<filed: bad attributes from filed n=%d : %s\n"),
293 + n, be.bstrerror());
297 + /* Now find all the files that are missing -- i.e. all files in
298 + * the database where the MarkId != current JobId
301 + bsnprintf(buf, sizeof(buf),
302 + "SELECT Path.Path,Filename.Name "
303 + "FROM CurrentBackup "
304 + "JOIN File USING (FileId) "
305 + "JOIN Path USING (PathId) "
306 + "JOIN Filename USING (FilenameId) "
307 + "WHERE CurrentBackup.BackupId=%s "
308 + "AND File.MarkId!=%d ",
309 + edit_uint64(backupid, ed1), edit_uint64(jcr->JobId, ed2));
310 + /* missing_handler is called for each file found */
311 + db_sql_query(jcr->db, buf, missing_handler, (void *)jcr);
313 + free_pool_memory(fname);
319 * Do a backup of the specified FileSet
321 * Returns: false on failure
327 + * If backup is in accurate mode, FD will send the list of
328 + * all files. We have to store it, and compute witch files
329 + * have been deleted and witch files have to be backuped.
331 + accurate_compute_files(jcr);
333 /* Pickup Job termination data */
334 stat = wait_for_job_termination(jcr);
335 db_write_batch_file_records(jcr); /* used by bulk batch file insert */
336 Index: src/dird/inc_conf.c
337 ===================================================================
338 --- src/dird/inc_conf.c (révision 6373)
339 +++ src/dird/inc_conf.c (copie de travail)
341 * Items that are valid in an Options resource
343 static RES_ITEM options_items[] = {
344 + {"accurate", store_opts, {0}, 0, 0, 0},
345 {"compression", store_opts, {0}, 0, 0, 0},
346 {"signature", store_opts, {0}, 0, 0, 0},
347 {"verify", store_opts, {0}, 0, 0, 0},
359 * options given above.
361 static struct s_kw FS_option_kw[] = {
362 + {"accurate", INC_KW_ACCURATE},
363 {"compression", INC_KW_COMPRESSION},
364 {"signature", INC_KW_DIGEST},
365 {"encryption", INC_KW_ENCRYPTION},
367 {"no", INC_KW_ENHANCEDWILD, "0"},
368 {"yes", INC_KW_CHKCHANGES, "c"},
369 {"no", INC_KW_CHKCHANGES, "0"},
370 + {"yes", INC_KW_ACCURATE, "C"},
371 + {"no", INC_KW_ACCURATE, "0"},
375 Index: src/dird/dird_conf.c
376 ===================================================================
377 --- src/dird/dird_conf.c (révision 6373)
378 +++ src/dird/dird_conf.c (copie de travail)
380 {"selectionpattern", store_str, ITEM(res_job.selection_pattern), 0, 0, 0},
381 {"runscript", store_runscript, ITEM(res_job.RunScripts), 0, ITEM_NO_EQUALS, 0},
382 {"selectiontype", store_migtype, ITEM(res_job.selection_type), 0, 0, 0},
383 + {"accuratebackup", store_bool, ITEM(res_job.accurate), 0,0,0},
384 {NULL, NULL, {0}, 0, 0, 0}
388 if (res->res_job.spool_size) {
389 sendit(sock, _(" SpoolSize=%s\n"), edit_uint64(res->res_job.spool_size, ed1));
391 + if (res->res_job.JobType == JT_BACKUP) {
392 + sendit(sock, _(" Accurate=%d\n"), res->res_job.accurate);
394 if (res->res_job.JobType == JT_MIGRATE) {
395 sendit(sock, _(" SelectionType=%d\n"), res->res_job.selection_type);
397 Index: src/dird/dird_conf.h
398 ===================================================================
399 --- src/dird/dird_conf.h (révision 6373)
400 +++ src/dird/dird_conf.h (copie de travail)
402 bool write_part_after_job; /* Set to write part after job in SD */
403 bool enabled; /* Set if job enabled */
404 bool OptimizeJobScheduling; /* Set if we should optimize Job scheduling */
405 + bool accurate; /* Set if it is an accurate backup job */
407 MSGS *messages; /* How and where to send messages */
408 SCHED *schedule; /* When -- Automatic schedule */
409 Index: src/filed/backup.c
410 ===================================================================
411 --- src/filed/backup.c (révision 6373)
412 +++ src/filed/backup.c (copie de travail)
414 static bool crypto_session_send(JCR *jcr, BSOCK *sd);
417 + * Called by save_file when accept/discard file for backup
419 + * TODO: we could add MD5/SHAX digest, but we have to compute it
422 +static bool accurate_add_file(JCR *jcr, FF_PKT *ff_pkt, char *stats)
425 + char attribs[MAXSTRING];
426 + uint32_t file_index=jcr->JobFiles;
427 + BSOCK *dir = jcr->dir_bsock;
430 + if (jcr->accurate == false || jcr->JobLevel == L_FULL) {
434 + if (!stats) { /* TODO: don't always compute attribute */
436 + encode_stat(attribs, ff_pkt, 0);
440 + switch (ff_pkt->type) {
441 + case FT_LNKSAVED: /* Hard linked, file already saved */
443 + stat = dir->fsend("%d %d %s %s%c%s%c%s%c", file_index,
444 + STREAM_UNIX_ATTRIBUTES, ff_pkt->VerifyOpts, ff_pkt->fname,
445 + 0, a, 0, ff_pkt->link, 0);
453 + stat = dir->fsend("%d %d %s %s%c%s%c%c", file_index,
454 + STREAM_UNIX_ATTRIBUTES, ff_pkt->VerifyOpts, ff_pkt->fname,
462 + stat = dir->fsend("%d %d %s %s%c%s%c%c", file_index,
463 + STREAM_UNIX_ATTRIBUTES, ff_pkt->VerifyOpts, ff_pkt->link,
467 + Dmsg2(1, _("Fname=%s Type=%i\n"), ff_pkt->fname, ff_pkt->type);
472 + Jmsg(jcr, M_FATAL, 0, _("Network error in send to Director: ERR=%s\n"), bnet_strerror(dir));
479 +/* build a fileset with new files from director */
480 +static bool accurate_get_new_and_deleted_file_list(JCR *jcr)
482 + if (jcr->accurate == false || job_canceled(jcr)) {
488 +/* send deleted file list to stored */
489 +static bool accurate_send_deleted_list(JCR *jcr)
491 + if (jcr->accurate == false || job_canceled(jcr)) {
497 +static bool accurate_send_file_list(JCR *jcr)
499 + if (jcr->accurate == false || job_canceled(jcr)) {
502 + Dmsg0(1, "Sending BNET_EOD\n");
503 + jcr->dir_bsock->signal(BNET_EOD); /* end of sending data */
509 * Find all the requested files and send them
510 * to the Storage daemon.
515 // TODO landonf: Allow user to specify encryption algorithm
516 + if (jcr->JobLevel != L_FULL) {
517 + jcr->accurate=true; /* TODO: remove that */
520 sd = jcr->store_bsock;
523 ok = false; /* error */
524 set_jcr_job_status(jcr, JS_ErrorTerminated);
526 + Dmsg1(1, "jcr->accurate == %i\n", jcr->accurate);
527 + /* start accurate stuffs */
528 + if (jcr->accurate) {
529 + /* TODO: test job_canceled() */
530 + accurate_send_file_list(jcr); /* send all files to DIR */
531 + accurate_get_new_and_deleted_file_list(jcr); /* get a new incr fileset from DIR */
532 +// set_find_options((FF_PKT *)jcr->ff, 0, 0); /* we backup all that director wants */
533 +// if (!find_files(jcr, (FF_PKT *)jcr->ff, save_file, (void *)jcr)) {
534 +// ok = false; /* error */
535 +// set_jcr_job_status(jcr, JS_ErrorTerminated);
537 +// accurate_send_file_list(jcr); /* send all new files to DIR */
538 + accurate_send_deleted_list(jcr); /* send deleted list to SD */
541 free_pool_memory(jcr->acl_text);
546 Jmsg(jcr, M_SKIPPED, 1, _(" Unchanged file skipped: %s\n"), ff_pkt->fname);
547 + accurate_add_file(jcr, ff_pkt, NULL); /* list skipped files */
550 Jmsg(jcr, M_NOTSAVED, 0, _(" Archive file not saved: %s\n"), ff_pkt->fname);
551 + accurate_add_file(jcr, ff_pkt, NULL); /* list skipped files */
555 @@ -1111,6 +1222,9 @@
557 unstrip_path(ff_pkt);
559 + /* list backuped files */
560 + accurate_add_file(jcr, ff_pkt, attribs);
562 Dmsg2(300, ">stored: attr len=%d: %s\n", sd->msglen, sd->msg);
564 Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
565 Index: src/filed/job.c
566 ===================================================================
567 --- src/filed/job.c (révision 6373)
568 +++ src/filed/job.c (copie de travail)
569 @@ -1087,6 +1087,9 @@
571 fo->flags |= FO_CHKCHANGES;
574 + fo->flags |= FO_ACCURATE;
577 Emsg1(M_ERROR, 0, _("Unknown include/exclude option: %c\n"), *p);
579 Index: src/cats/make_postgresql_tables.in
580 ===================================================================
581 --- src/cats/make_postgresql_tables.in (révision 6373)
582 +++ src/cats/make_postgresql_tables.in (copie de travail)
584 CREATE INDEX file_jobid_idx on file (jobid);
585 CREATE INDEX file_fp_idx on file (filenameid, pathid);
587 +CREATE TABLE CurrentBackupId
589 + BackupId serial not null,
590 + ClientId integer not null,
591 + JobName text not null,
592 + FileSetId integer not null,
593 + primary key (BackupId)
596 +-- Serait bien de prendre la meme table pour
597 +-- les File et le CurrentBackup...
598 +-- Mais y'a des problemes pour les prunes
600 +CREATE TABLE CurrentBackup
602 + FileId integer not null,
603 + BackupId integer not null,
604 + FullMark char(1) default 0,
605 + primary key (FileId)
608 +CREATE INDEX currentbackup_fileid on CurrentBackup (BackupId);
610 +-- CREATE TEMPORARY TABLE batch (fileindex int,
617 +-- -- On batch insert dans la table temporaire
619 +-- il faut trouver les fichiers manquant
620 +-- INSERT des nouveaux, UPDATE des anciens, SELECT pour trouver les deletes
623 +-- il faut trouver les fichiers modifies
624 +-- Le champs LStat n'est plus le meme
626 +-- FROM CurrentBackup,
627 +-- batch JOIN Path USING (Path) JOIN Filename USING (Name)
628 +-- WHERE Path.PathId = CurrentBackup.PathId
629 +-- AND Filename.FilenameId = CurrentBackup.FilenameId
630 +-- AND CurrentBackup.LStat != batch.LStat
632 +-- il faut mettre a jour la liste des fichiers
640 -- Possibly add one or more of the following indexes
641 -- if your Verifies are too slow.
642 Index: src/cats/protos.h
643 ===================================================================
644 --- src/cats/protos.h (révision 6373)
645 +++ src/cats/protos.h (copie de travail)
648 bool db_find_job_start_time(JCR *jcr, B_DB *mdb, JOB_DBR *jr, POOLMEM **stime);
649 bool db_find_last_jobid(JCR *jcr, B_DB *mdb, const char *Name, JOB_DBR *jr);
650 +JobId_t db_find_backupid(JCR *jcr, B_DB *mdb, JOB_DBR *jr);
651 int db_find_next_volume(JCR *jcr, B_DB *mdb, int index, bool InChanger, MEDIA_DBR *mr);
652 bool db_find_failed_job_since(JCR *jcr, B_DB *mdb, JOB_DBR *jr, POOLMEM *stime, int &JobLevel);
655 +int db_accurate_get_file_attributes_record(JCR *jcr, B_DB *mdb, char *fname, JobId_t backupid, FILE_DBR *fdbr);
656 bool db_get_pool_record(JCR *jcr, B_DB *db, POOL_DBR *pdbr);
657 int db_get_client_record(JCR *jcr, B_DB *mdb, CLIENT_DBR *cr);
658 bool db_get_job_record(JCR *jcr, B_DB *mdb, JOB_DBR *jr);
659 Index: src/cats/sql_find.c
660 ===================================================================
661 --- src/cats/sql_find.c (révision 6373)
662 +++ src/cats/sql_find.c (copie de travail)
668 + * Find BackupId of last job that ran. E.g. for
670 + * Returns: Last backuip
674 +db_find_backupid(JCR *jcr, B_DB *mdb, JOB_DBR *jr)
677 + char ed1[50],ed2[50];
678 + JobId_t backupid=0;
680 + /* Find backupid */
682 + Dmsg2(100, "JobLevel=%d JobType=%d\n", jcr->JobLevel, jcr->JobType);
684 +"SELECT BackupId FROM CurrentBackupId WHERE JobName='%s' AND "
685 +"ClientId=%s AND FileSetId=%s ORDER BY BackupId DESC LIMIT 1",
687 + edit_int64(jr->ClientId, ed1),
688 + edit_int64(jr->FileSetId, ed2));
690 + Dmsg1(100, "Query: %s\n", mdb->cmd);
691 + if (!QUERY_DB(jcr, mdb, mdb->cmd)) {
695 + if ((row = sql_fetch_row(mdb)) == NULL) {
696 + Mmsg1(&mdb->errmsg, _("No Job found for: %s.\n"), mdb->cmd);
697 + sql_free_result(mdb);
702 + backupid = str_to_int64(row[0]);
703 + sql_free_result(mdb);
705 + if (backupid <= 0) {
706 + Mmsg1(&mdb->errmsg, _("No Job found for: %s\n"), mdb->cmd);
717 * Find JobId of last job that ran. E.g. for
718 * VERIFY_CATALOG we want the JobId of the last INIT.
719 Index: src/cats/sql_create.c
720 ===================================================================
721 --- src/cats/sql_create.c (révision 6373)
722 +++ src/cats/sql_create.c (copie de travail)
727 +bool db_accurate_insert(JCR *jcr, B_DB *mdb, bool saved, const char *fname, struct stat *stat)
730 + split_path_and_file(jcr, mdb, fname);
731 + /* make like in Verify code */
736 * Create File record in B_DB
738 Index: src/cats/sql_get.c
739 ===================================================================
740 --- src/cats/sql_get.c (révision 6373)
741 +++ src/cats/sql_get.c (copie de travail)
744 * Returns: 0 on failure
745 * 1 on success with the File record in FILE_DBR
747 + * TODO: optimize this with only one query
749 int db_get_file_attributes_record(JCR *jcr, B_DB *mdb, char *fname, JOB_DBR *jr, FILE_DBR *fdbr)
756 + * Given a full filename (with path), look up the File record
757 + * (with attributes) in the database.
759 + * Returns: 0 on failure
760 + * 1 on success with the File record in FILE_DBR
762 +int db_accurate_get_file_attributes_record(JCR *jcr, B_DB *mdb, char *fname, JobId_t backupid, FILE_DBR *fdbr)
769 + split_path_and_file(jcr, mdb, fname);
771 + mdb->esc_name = check_pool_memory_size(mdb->esc_name, 2*mdb->fnl+2);
772 + db_escape_string(jcr, mdb, mdb->esc_name, mdb->fname, mdb->fnl);
774 + mdb->esc_path = check_pool_memory_size(mdb->esc_path, 2*mdb->pnl+2);
775 + db_escape_string(jcr, mdb, mdb->esc_path, mdb->path, mdb->pnl);
778 +"SELECT FileId, LStat, MD5, FilenameId, PathId, FileIndex, MarkId, JobId "
779 + "FROM File JOIN CurrentBackup USING (FileId) "
780 + "JOIN Filename USING (FilenameId) "
781 + "JOIN Path USING (PathId) "
782 + "WHERE Path.Path='%s' "
783 + "AND Filename.Name='%s' "
784 + "AND BackupId=%s ",
787 + edit_int64(backupid, ed1));
789 + Dmsg1(1,"get_file %s\n", mdb->cmd);
791 + if (QUERY_DB(jcr, mdb, mdb->cmd)) {
793 + mdb->num_rows = sql_num_rows(mdb);
794 + if (mdb->num_rows == 1) {
795 + if ((row = sql_fetch_row(mdb)) == NULL) {
796 + Mmsg1(mdb->errmsg, _("error fetching row: %s\n"), sql_strerror(mdb));
798 + fdbr->FileId = str_to_int64(row[0]);
799 + bstrncpy(fdbr->LStat, row[1], sizeof(fdbr->LStat));
800 + bstrncpy(fdbr->Digest, row[2], sizeof(fdbr->Digest));
801 + fdbr->FilenameId = str_to_int64(row[3]);
802 + fdbr->PathId = str_to_int64(row[4]);
803 + fdbr->FileIndex = str_to_int64(row[5]);
804 + fdbr->MarkId = str_to_int64(row[6]);
805 + fdbr->JobId = str_to_int64(row[7]);
809 + Mmsg2(mdb->errmsg, _("Get DB File record %s failed num=%i\n"),fname,mdb->num_rows);
810 + Jmsg(jcr, M_WARNING, 0, "%s", mdb->errmsg);
812 + sql_free_result(mdb);
814 + Mmsg(mdb->errmsg, _("File record: %s not found in Catalog for BackupId=%s.\n"), fname, ed1);
824 * Returns: 0 on failure
826 ===================================================================
827 --- src/jcr.h (révision 6373)
828 +++ src/jcr.h (copie de travail)
830 B_DB *db_batch; /* database pointer for batch insert */
831 ATTR_DBR *ar; /* DB attribute record */
832 guid_list *id_list; /* User/group id to name list */
833 + bool accurate; /* true if job is accurate */
835 void *plugin_ctx_list; /* list of contexts for plugins */
836 void *plugin_ctx; /* current plugin context */
837 Index: src/findlib/find.h
838 ===================================================================
839 --- src/findlib/find.h (révision 6373)
840 +++ src/findlib/find.h (copie de travail)
842 #define FO_ENHANCEDWILD (1<<23) /* Enhanced wild card processing */
843 #define FO_CHKCHANGES (1<<24) /* Check if file have been modified during backup */
844 #define FO_STRIPPATH (1<<25) /* Check for stripping path */
845 +#define FO_ACCURATE (1<<26) /* Accurate mode */
847 struct s_included_file {
848 struct s_included_file *next;