]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/filed/accurate.c
Loose #ifdef and use const bool wrapper for some cleaner coding.
[bacula/bacula] / bacula / src / filed / accurate.c
1 /*
2    Bacula® - The Network Backup Solution
3
4    Copyright (C) 2000-2009 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 bool accurate_mark_file_as_seen(JCR *jcr, char *fname)
47 {
48    if (!jcr->accurate || !jcr->file_list) {
49       return false;
50    }
51    /* TODO: just use elt->seen = 1 */
52    CurFile *temp = (CurFile *)jcr->file_list->lookup(fname);
53    if (temp) {
54       temp->seen = 1;              /* records are in memory */
55       Dmsg1(dbglvl, "marked <%s> as seen\n", fname);
56    } else {
57       Dmsg1(dbglvl, "<%s> not found to be marked as seen\n", fname);
58    }
59    return true;
60 }
61
62 static bool accurate_mark_file_as_seen(JCR *jcr, CurFile *elt)
63 {
64    /* TODO: just use elt->seen = 1 */
65    CurFile *temp = (CurFile *)jcr->file_list->lookup(elt->fname);
66    if (temp) {
67       temp->seen = 1;              /* records are in memory */
68    }
69    return true;
70 }
71
72 static bool accurate_lookup(JCR *jcr, char *fname, CurFile *ret)
73 {
74    bool found=false;
75    ret->seen = 0;
76
77    CurFile *temp = (CurFile *)jcr->file_list->lookup(fname);
78    if (temp) {
79       memcpy(ret, temp, sizeof(CurFile));
80       found=true;
81       Dmsg1(dbglvl, "lookup <%s> ok\n", fname);
82    }
83
84    return found;
85 }
86
87 static bool accurate_init(JCR *jcr, int nbfile)
88 {
89    CurFile *elt = NULL;
90    jcr->file_list = (htable *)malloc(sizeof(htable));
91    jcr->file_list->init(elt, &elt->link, nbfile);
92    return true;
93 }
94
95 /* This function is called at the end of backup
96  * We walk over all hash disk element, and we check
97  * for elt.seen.
98  */
99 bool accurate_send_deleted_list(JCR *jcr)
100 {
101    CurFile *elt;
102    FF_PKT *ff_pkt;
103    int stream = STREAM_UNIX_ATTRIBUTES;
104
105    if (!jcr->accurate || jcr->get_JobLevel() == L_FULL) {
106       goto bail_out;
107    }
108
109    if (jcr->file_list == NULL) {
110       goto bail_out;
111    }
112
113    ff_pkt = init_find_files();
114    ff_pkt->type = FT_DELETED;
115
116    foreach_htable(elt, jcr->file_list) {
117       if (elt->seen || plugin_check_file(jcr, elt->fname)) {
118          continue;
119       }
120       Dmsg2(dbglvl, "deleted fname=%s seen=%i\n", elt->fname, elt->seen);
121       ff_pkt->fname = elt->fname;
122       ff_pkt->statp.st_mtime = elt->mtime;
123       ff_pkt->statp.st_ctime = elt->ctime;
124       encode_and_send_attributes(jcr, ff_pkt, stream);
125 //    free(elt->fname);
126    }
127
128    term_find_files(ff_pkt);
129 bail_out:
130    /* TODO: clean htable when this function is not reached ? */
131    accurate_free(jcr);
132    return true;
133 }
134
135 void accurate_free(JCR *jcr)
136 {
137    if (jcr->file_list) {
138       jcr->file_list->destroy();
139       free(jcr->file_list);
140       jcr->file_list = NULL;
141    }
142 }
143
144 static bool accurate_add_file(JCR *jcr, char *fname, char *lstat)
145 {
146    bool ret = true;
147    CurFile elt;
148    struct stat statp;
149    int32_t LinkFIc;
150    decode_stat(lstat, &statp, &LinkFIc); /* decode catalog stat */
151    elt.ctime = statp.st_ctime;
152    elt.mtime = statp.st_mtime;
153    elt.seen = 0;
154
155    CurFile *item;
156    /* we store CurFile, fname and ctime/mtime in the same chunk */
157    item = (CurFile *)jcr->file_list->hash_malloc(sizeof(CurFile)+strlen(fname)+1);
158    memcpy(item, &elt, sizeof(CurFile));
159    item->fname  = (char *)item+sizeof(CurFile);
160    strcpy(item->fname, fname);
161    jcr->file_list->insert(item->fname, item); 
162
163    Dmsg2(dbglvl, "add fname=<%s> lstat=%s\n", fname, lstat);
164    return ret;
165 }
166
167 /*
168  * This function is called for each file seen in fileset.
169  * We check in file_list hash if fname have been backuped
170  * the last time. After we can compare Lstat field. 
171  * Full Lstat usage have been removed on 6612 
172  *
173  * Returns: true   if file has changed (must be backed up)
174  *          false  file not changed
175  */
176 bool accurate_check_file(JCR *jcr, FF_PKT *ff_pkt)
177 {
178    bool stat = false;
179    char *fname;
180    CurFile elt;
181
182    if (!jcr->accurate || jcr->get_JobLevel() == L_FULL) {
183       return true;
184    }
185
186    strip_path(ff_pkt);
187  
188    if (S_ISDIR(ff_pkt->statp.st_mode)) {
189       fname = ff_pkt->link;
190    } else {
191       fname = ff_pkt->fname;
192    } 
193
194    if (!accurate_lookup(jcr, fname, &elt)) {
195       Dmsg1(dbglvl, "accurate %s (not found)\n", fname);
196       stat = true;
197       goto bail_out;
198    }
199
200    if (elt.seen) { /* file has been seen ? */
201       Dmsg1(dbglvl, "accurate %s (already seen)\n", fname);
202       goto bail_out;
203    }
204
205    /*
206     * We check only mtime/ctime like with the normal
207     * incremental/differential mode
208     */
209    if (elt.mtime != ff_pkt->statp.st_mtime) {
210 //   Jmsg(jcr, M_SAVED, 0, _("%s      st_mtime differs\n"), fname);
211       Dmsg3(dbglvl, "%s      st_mtime differs (%lld!=%lld)\n", 
212             fname, elt.mtime, (utime_t)ff_pkt->statp.st_mtime);
213      stat = true;
214    } else if (!(ff_pkt->flags & FO_MTIMEONLY) 
215               && (elt.ctime != ff_pkt->statp.st_ctime)) {
216 //   Jmsg(jcr, M_SAVED, 0, _("%s      st_ctime differs\n"), fname);
217       Dmsg3(dbglvl, "%s      st_ctime differs\n", 
218             fname, elt.ctime, ff_pkt->statp.st_ctime);
219      stat = true;
220    }
221
222    accurate_mark_file_as_seen(jcr, &elt);
223 //   Dmsg2(dbglvl, "accurate %s = %d\n", fname, stat);
224
225 bail_out:
226    unstrip_path(ff_pkt);
227    return stat;
228 }
229
230 /* 
231  * TODO: use big buffer from htable
232  */
233 int accurate_cmd(JCR *jcr)
234 {
235    BSOCK *dir = jcr->dir_bsock;
236    int len;
237    int32_t nb;
238
239    if (!jcr->accurate || job_canceled(jcr) || jcr->get_JobLevel()==L_FULL) {
240       return true;
241    }
242    if (sscanf(dir->msg, "accurate files=%ld", &nb) != 1) {
243       dir->fsend(_("2991 Bad accurate command\n"));
244       return false;
245    }
246
247    accurate_init(jcr, nb);
248
249    /*
250     * buffer = sizeof(CurFile) + dirmsg
251     * dirmsg = fname + \0 + lstat
252     */
253    /* get current files */
254    while (dir->recv() >= 0) {
255       len = strlen(dir->msg) + 1;
256       if (len < dir->msglen) {
257          accurate_add_file(jcr, dir->msg, dir->msg + len);
258       }
259    }
260
261 #ifdef DEBUG
262    extern void *start_heap;
263
264    char b1[50], b2[50], b3[50], b4[50], b5[50];
265    Dmsg5(dbglvl," Heap: heap=%s smbytes=%s max_bytes=%s bufs=%s max_bufs=%s\n",
266          edit_uint64_with_commas((char *)sbrk(0)-(char *)start_heap, b1),
267          edit_uint64_with_commas(sm_bytes, b2),
268          edit_uint64_with_commas(sm_max_bytes, b3),
269          edit_uint64_with_commas(sm_buffers, b4),
270          edit_uint64_with_commas(sm_max_buffers, b5));
271 #endif
272
273    return true;
274 }