]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/filed/accurate.c
e7fd6447208a9a58a75134e40eed993e0677d16c
[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    if (elt.mtime != ff_pkt->statp.st_mtime) {
181 //   Jmsg(jcr, M_SAVED, 0, _("%s      st_mtime differs\n"), fname);
182       Dmsg3(dbglvl, "%s      st_mtime differs (%i!=%i)\n", 
183             fname, elt.mtime, ff_pkt->statp.st_mtime);
184      stat = true;
185    } else if (elt.ctime != ff_pkt->statp.st_ctime) {
186 //   Jmsg(jcr, M_SAVED, 0, _("%s      st_ctime differs\n"), fname);
187       Dmsg3(dbglvl, "%s      st_ctime differs\n", 
188             fname, elt.ctime, ff_pkt->statp.st_ctime);
189      stat = true;
190    }
191
192    accurate_mark_file_as_seen(jcr, &elt);
193 //   Dmsg2(dbglvl, "accurate %s = %i\n", fname, stat);
194
195 bail_out:
196    unstrip_path(ff_pkt);
197    return stat;
198 }
199
200 /* 
201  * TODO: use big buffer from htable
202  */
203 int accurate_cmd(JCR *jcr)
204 {
205    BSOCK *dir = jcr->dir_bsock;
206    int len;
207    int32_t nb;
208
209    if (!jcr->accurate || job_canceled(jcr) || jcr->get_JobLevel()==L_FULL) {
210       return true;
211    }
212
213    if (sscanf(dir->msg, "accurate files=%ld", &nb) != 1) {
214       dir->fsend(_("2991 Bad accurate command\n"));
215       return false;
216    }
217
218    accurate_init(jcr, nb);
219
220    /*
221     * buffer = sizeof(CurFile) + dirmsg
222     * dirmsg = fname + \0 + lstat
223     */
224    /* get current files */
225    while (dir->recv() >= 0) {
226       len = strlen(dir->msg) + 1;
227       if (len < dir->msglen) {
228          accurate_add_file(jcr, dir->msg, dir->msg + len);
229       }
230    }
231
232 #ifdef DEBUG
233    extern void *start_heap;
234
235    char b1[50], b2[50], b3[50], b4[50], b5[50];
236    Dmsg5(dbglvl," Heap: heap=%s smbytes=%s max_bytes=%s bufs=%s max_bufs=%s\n",
237          edit_uint64_with_commas((char *)sbrk(0)-(char *)start_heap, b1),
238          edit_uint64_with_commas(sm_bytes, b2),
239          edit_uint64_with_commas(sm_max_bytes, b3),
240          edit_uint64_with_commas(sm_buffers, b4),
241          edit_uint64_with_commas(sm_max_buffers, b5));
242 #endif
243
244    return true;
245 }