]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/filed/accurate.c
ebl Use MTIMEONLY fileset option in accurate check
[bacula/bacula] / bacula / src / filed / accurate.c
1 /*
2    Bacula® - The Network Backup Solution
3
4    Copyright (C) 2000-2008 Free Software Foundation Europe e.V.
5
6    The main author of Bacula is Kern Sibbald, with contributions from
7    many others, a complete list can be found in the file AUTHORS.
8    This program is Free Software; you can redistribute it and/or
9    modify it under the terms of version two of the GNU General Public
10    License as published by the Free Software Foundation and included
11    in the file LICENSE.
12
13    This program is distributed in the hope that it will be useful, but
14    WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16    General Public License for more details.
17
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21    02110-1301, USA.
22
23    Bacula® is a registered trademark of Kern Sibbald.
24    The licensor of Bacula is the Free Software Foundation Europe
25    (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
26    Switzerland, email:ftf@fsfeurope.org.
27 */
28 /*
29  *  Version $Id $
30  *
31  */
32
33 #include "bacula.h"
34 #include "filed.h"
35
36 static int dbglvl=200;
37
38 typedef struct PrivateCurFile {
39    hlink link;
40    char *fname;
41    utime_t ctime;
42    utime_t mtime;
43    bool seen;
44 } CurFile;
45
46 static bool accurate_mark_file_as_seen(JCR *jcr, CurFile *elt)
47 {
48    /* TODO: just use elt->seen = 1 */
49    CurFile *temp = (CurFile *)jcr->file_list->lookup(elt->fname);
50    if (temp) {
51       temp->seen = 1;              /* records are in memory */
52    }
53    return true;
54 }
55
56 static bool accurate_lookup(JCR *jcr, char *fname, CurFile *ret)
57 {
58    bool found=false;
59    ret->seen = 0;
60
61    CurFile *temp = (CurFile *)jcr->file_list->lookup(fname);
62    if (temp) {
63       memcpy(ret, temp, sizeof(CurFile));
64       found=true;
65       Dmsg1(dbglvl, "lookup <%s> ok\n", fname);
66    }
67
68    return found;
69 }
70
71 static bool accurate_init(JCR *jcr, int nbfile)
72 {
73    CurFile *elt = NULL;
74    jcr->file_list = (htable *)malloc(sizeof(htable));
75    jcr->file_list->init(elt, &elt->link, nbfile);
76    return true;
77 }
78
79 /* This function is called at the end of backup
80  * We walk over all hash disk element, and we check
81  * for elt.seen.
82  */
83 bool accurate_send_deleted_list(JCR *jcr)
84 {
85    CurFile *elt;
86    FF_PKT *ff_pkt;
87    int stream = STREAM_UNIX_ATTRIBUTES;
88
89    if (!jcr->accurate || jcr->get_JobLevel() == L_FULL) {
90       goto bail_out;
91    }
92
93    if (jcr->file_list == NULL) {
94       goto bail_out;
95    }
96
97    ff_pkt = init_find_files();
98    ff_pkt->type = FT_DELETED;
99
100    foreach_htable(elt, jcr->file_list) {
101       if (!elt->seen) { /* already seen */
102          Dmsg2(dbglvl, "deleted fname=%s seen=%i\n", elt->fname, elt->seen);
103          ff_pkt->fname = elt->fname;
104          ff_pkt->statp.st_mtime = elt->mtime;
105          ff_pkt->statp.st_ctime = elt->ctime;
106          encode_and_send_attributes(jcr, ff_pkt, stream);
107       }
108 //      free(elt->fname);
109    }
110
111    term_find_files(ff_pkt);
112 bail_out:
113    /* TODO: clean htable when this function is not reached ? */
114    if (jcr->file_list) {
115       jcr->file_list->destroy();
116       free(jcr->file_list);
117       jcr->file_list = NULL;
118    }
119    return true;
120 }
121
122 static bool accurate_add_file(JCR *jcr, char *fname, char *lstat)
123 {
124    bool ret = true;
125    CurFile elt;
126    struct stat statp;
127    int LinkFIc;
128    decode_stat(lstat, &statp, &LinkFIc); /* decode catalog stat */
129    elt.ctime = statp.st_ctime;
130    elt.mtime = statp.st_mtime;
131    elt.seen = 0;
132
133    CurFile *item;
134    /* we store CurFile, fname and ctime/mtime in the same chunk */
135    item = (CurFile *)jcr->file_list->hash_malloc(sizeof(CurFile)+strlen(fname)+1);
136    memcpy(item, &elt, sizeof(CurFile));
137    item->fname  = (char *)item+sizeof(CurFile);
138    strcpy(item->fname, fname);
139    jcr->file_list->insert(item->fname, item); 
140
141    Dmsg2(dbglvl, "add fname=<%s> lstat=%s\n", fname, lstat);
142    return ret;
143 }
144
145 /*
146  * This function is called for each file seen in fileset.
147  * We check in file_list hash if fname have been backuped
148  * the last time. After we can compare Lstat field. 
149  * Full Lstat usage have been removed on 6612 
150  */
151 bool accurate_check_file(JCR *jcr, FF_PKT *ff_pkt)
152 {
153    bool stat = false;
154    char *fname;
155    CurFile elt;
156
157    if (!jcr->accurate || jcr->get_JobLevel() == L_FULL) {
158       return true;
159    }
160
161    strip_path(ff_pkt);
162  
163    if (S_ISDIR(ff_pkt->statp.st_mode)) {
164       fname = ff_pkt->link;
165    } else {
166       fname = ff_pkt->fname;
167    } 
168
169    if (!accurate_lookup(jcr, fname, &elt)) {
170       Dmsg1(dbglvl, "accurate %s (not found)\n", fname);
171       stat = true;
172       goto bail_out;
173    }
174
175    if (elt.seen) { /* file has been seen ? */
176       Dmsg1(dbglvl, "accurate %s (already seen)\n", fname);
177       goto bail_out;
178    }
179
180    /*
181     * We check only mtime/ctime like with the normal
182     * incremental/differential mode
183     */
184    if (elt.mtime != ff_pkt->statp.st_mtime) {
185 //   Jmsg(jcr, M_SAVED, 0, _("%s      st_mtime differs\n"), fname);
186       Dmsg3(dbglvl, "%s      st_mtime differs (%i!=%i)\n", 
187             fname, elt.mtime, ff_pkt->statp.st_mtime);
188      stat = true;
189    } else if (!(ff_pkt->flags & FO_MTIMEONLY) 
190               && (elt.ctime != ff_pkt->statp.st_ctime)) {
191 //   Jmsg(jcr, M_SAVED, 0, _("%s      st_ctime differs\n"), fname);
192       Dmsg3(dbglvl, "%s      st_ctime differs\n", 
193             fname, elt.ctime, ff_pkt->statp.st_ctime);
194      stat = true;
195    }
196
197    accurate_mark_file_as_seen(jcr, &elt);
198 //   Dmsg2(dbglvl, "accurate %s = %i\n", fname, stat);
199
200 bail_out:
201    unstrip_path(ff_pkt);
202    return stat;
203 }
204
205 /* 
206  * TODO: use big buffer from htable
207  */
208 int accurate_cmd(JCR *jcr)
209 {
210    BSOCK *dir = jcr->dir_bsock;
211    int len;
212    int32_t nb;
213
214    if (!jcr->accurate || job_canceled(jcr) || jcr->get_JobLevel()==L_FULL) {
215       return true;
216    }
217
218    if (sscanf(dir->msg, "accurate files=%ld", &nb) != 1) {
219       dir->fsend(_("2991 Bad accurate command\n"));
220       return false;
221    }
222
223    accurate_init(jcr, nb);
224
225    /*
226     * buffer = sizeof(CurFile) + dirmsg
227     * dirmsg = fname + \0 + lstat
228     */
229    /* get current files */
230    while (dir->recv() >= 0) {
231       len = strlen(dir->msg) + 1;
232       if (len < dir->msglen) {
233          accurate_add_file(jcr, dir->msg, dir->msg + len);
234       }
235    }
236
237 #ifdef DEBUG
238    extern void *start_heap;
239
240    char b1[50], b2[50], b3[50], b4[50], b5[50];
241    Dmsg5(dbglvl," Heap: heap=%s smbytes=%s max_bytes=%s bufs=%s max_bufs=%s\n",
242          edit_uint64_with_commas((char *)sbrk(0)-(char *)start_heap, b1),
243          edit_uint64_with_commas(sm_bytes, b2),
244          edit_uint64_with_commas(sm_max_bytes, b3),
245          edit_uint64_with_commas(sm_buffers, b4),
246          edit_uint64_with_commas(sm_max_buffers, b5));
247 #endif
248
249    return true;
250 }