]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/filed/accurate.c
d7ff0437573a5c3c59bc15a7035703566d5a22d3
[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    if (jcr->file_list) {
132       jcr->file_list->destroy();
133       free(jcr->file_list);
134       jcr->file_list = NULL;
135    }
136    return true;
137 }
138
139 static bool accurate_add_file(JCR *jcr, char *fname, char *lstat)
140 {
141    bool ret = true;
142    CurFile elt;
143    struct stat statp;
144    int LinkFIc;
145    decode_stat(lstat, &statp, &LinkFIc); /* decode catalog stat */
146    elt.ctime = statp.st_ctime;
147    elt.mtime = statp.st_mtime;
148    elt.seen = 0;
149
150    CurFile *item;
151    /* we store CurFile, fname and ctime/mtime in the same chunk */
152    item = (CurFile *)jcr->file_list->hash_malloc(sizeof(CurFile)+strlen(fname)+1);
153    memcpy(item, &elt, sizeof(CurFile));
154    item->fname  = (char *)item+sizeof(CurFile);
155    strcpy(item->fname, fname);
156    jcr->file_list->insert(item->fname, item); 
157
158    Dmsg2(dbglvl, "add fname=<%s> lstat=%s\n", fname, lstat);
159    return ret;
160 }
161
162 /*
163  * This function is called for each file seen in fileset.
164  * We check in file_list hash if fname have been backuped
165  * the last time. After we can compare Lstat field. 
166  * Full Lstat usage have been removed on 6612 
167  */
168 bool accurate_check_file(JCR *jcr, FF_PKT *ff_pkt)
169 {
170    bool stat = false;
171    char *fname;
172    CurFile elt;
173
174    if (!jcr->accurate || jcr->get_JobLevel() == L_FULL) {
175       return true;
176    }
177
178    strip_path(ff_pkt);
179  
180    if (S_ISDIR(ff_pkt->statp.st_mode)) {
181       fname = ff_pkt->link;
182    } else {
183       fname = ff_pkt->fname;
184    } 
185
186    if (!accurate_lookup(jcr, fname, &elt)) {
187       Dmsg1(dbglvl, "accurate %s (not found)\n", fname);
188       stat = true;
189       goto bail_out;
190    }
191
192    if (elt.seen) { /* file has been seen ? */
193       Dmsg1(dbglvl, "accurate %s (already seen)\n", fname);
194       goto bail_out;
195    }
196
197    /*
198     * We check only mtime/ctime like with the normal
199     * incremental/differential mode
200     */
201    if (elt.mtime != ff_pkt->statp.st_mtime) {
202 //   Jmsg(jcr, M_SAVED, 0, _("%s      st_mtime differs\n"), fname);
203       Dmsg3(dbglvl, "%s      st_mtime differs (%i!=%i)\n", 
204             fname, elt.mtime, ff_pkt->statp.st_mtime);
205      stat = true;
206    } else if (!(ff_pkt->flags & FO_MTIMEONLY) 
207               && (elt.ctime != ff_pkt->statp.st_ctime)) {
208 //   Jmsg(jcr, M_SAVED, 0, _("%s      st_ctime differs\n"), fname);
209       Dmsg3(dbglvl, "%s      st_ctime differs\n", 
210             fname, elt.ctime, ff_pkt->statp.st_ctime);
211      stat = true;
212    }
213
214    accurate_mark_file_as_seen(jcr, &elt);
215 //   Dmsg2(dbglvl, "accurate %s = %i\n", fname, stat);
216
217 bail_out:
218    unstrip_path(ff_pkt);
219    return stat;
220 }
221
222 /* 
223  * TODO: use big buffer from htable
224  */
225 int accurate_cmd(JCR *jcr)
226 {
227    BSOCK *dir = jcr->dir_bsock;
228    int len;
229    int32_t nb;
230
231    if (!jcr->accurate || job_canceled(jcr) || jcr->get_JobLevel()==L_FULL) {
232       return true;
233    }
234
235    if (sscanf(dir->msg, "accurate files=%ld", &nb) != 1) {
236       dir->fsend(_("2991 Bad accurate command\n"));
237       return false;
238    }
239
240    accurate_init(jcr, nb);
241
242    /*
243     * buffer = sizeof(CurFile) + dirmsg
244     * dirmsg = fname + \0 + lstat
245     */
246    /* get current files */
247    while (dir->recv() >= 0) {
248       len = strlen(dir->msg) + 1;
249       if (len < dir->msglen) {
250          accurate_add_file(jcr, dir->msg, dir->msg + len);
251       }
252    }
253
254 #ifdef DEBUG
255    extern void *start_heap;
256
257    char b1[50], b2[50], b3[50], b4[50], b5[50];
258    Dmsg5(dbglvl," Heap: heap=%s smbytes=%s max_bytes=%s bufs=%s max_bufs=%s\n",
259          edit_uint64_with_commas((char *)sbrk(0)-(char *)start_heap, b1),
260          edit_uint64_with_commas(sm_bytes, b2),
261          edit_uint64_with_commas(sm_max_bytes, b3),
262          edit_uint64_with_commas(sm_buffers, b4),
263          edit_uint64_with_commas(sm_max_buffers, b5));
264 #endif
265
266    return true;
267 }