2 Bacula® - The Network Backup Solution
4 Copyright (C) 2000-2008 Free Software Foundation Europe e.V.
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
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.
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
23 Bacula® is a registered trademark of John Walker.
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.
36 typedef struct PrivateCurFile {
40 char *fname; /* not stored with tchdb mode */
48 static bool accurate_mark_file_as_seen(JCR *jcr, CurFile *elt)
53 if (!tchdbputasync(jcr->file_list,
54 elt->fname, strlen(elt->fname)+1,
55 elt, sizeof(CurFile)))
57 Dmsg1(2, "can't update <%s>\n", elt->fname);
58 ret = false; /* TODO: add error message */
64 static bool accurate_lookup(JCR *jcr, char *fname, CurFile *ret)
69 if (tchdbget3(jcr->file_list,
70 fname, strlen(fname)+1,
71 ret, sizeof(CurFile)) != -1)
78 Dmsg1(2, "lookup <%s> ok\n", fname);
84 static bool accurate_init(JCR *jcr, int nbfile)
86 jcr->file_list = tchdbnew();
87 tchdbsetcache(jcr->file_list, 300000);
88 tchdbtune(jcr->file_list,
89 nbfile, /* nb bucket 0.5n to 4n */
90 6, /* size of element 2^x */
92 0); /* options like compression */
93 /* TODO: make accurate file unique */
94 POOLMEM *name = get_pool_memory(PM_MESSAGE);
95 make_unique_filename(name, jcr->JobId, "accurate");
97 if(!tchdbopen(jcr->file_list, name, HDBOWRITER | HDBOCREAT)){
98 /* TODO: handle error creation */
99 //ecode = tchdbecode(hdb);
100 //fprintf(stderr, "open error: %s\n", tchdberrmsg(ecode));
102 free_pool_memory(name);
107 bool accurate_send_deleted_list(JCR *jcr)
111 int stream = STREAM_UNIX_ATTRIBUTES;
113 if (!jcr->accurate || jcr->JobLevel == L_FULL) {
117 if (jcr->file_list == NULL) {
121 ff_pkt = init_find_files();
122 ff_pkt->type = FT_DELETED;
125 /* traverse records */
126 tchdbiterinit(jcr->file_list);
127 while((key = tchdbiternext2(jcr->file_list)) != NULL) {
128 if (tchdbget3(jcr->file_list,
130 &elt, sizeof(CurFile)) != -1)
134 ff_pkt->statp.st_mtime = elt.mtime;
135 ff_pkt->statp.st_ctime = elt.ctime;
136 encode_and_send_attributes(jcr, ff_pkt, stream);
137 Dmsg1(2, "deleted <%s>\n", key);
141 } else { /* TODO: add error message */
142 Dmsg1(2, "No value for <%s> key\n", key);
146 term_find_files(ff_pkt);
148 /* TODO: clean htable when this function is not reached ? */
149 if (jcr->file_list) {
150 if(!tchdbclose(jcr->file_list)){
151 // ecode = tchdbecode(hdb);
152 // fprintf(stderr, "close error: %s\n", tchdberrmsg(ecode));
155 /* delete the object */
156 tchdbdel(jcr->file_list);
158 POOLMEM *name = get_pool_memory(PM_MESSAGE);
159 make_unique_filename(name, jcr->JobId, "accurate");
163 free_pool_memory(name);
165 jcr->file_list = NULL;
170 #else /* HTABLE mode */
172 static bool accurate_mark_file_as_seen(JCR *jcr, CurFile *elt)
174 CurFile *temp = (CurFile *)jcr->file_list->lookup(elt->fname);
175 temp->seen = 1; /* records are in memory */
179 static bool accurate_lookup(JCR *jcr, char *fname, CurFile *ret)
184 CurFile *temp = (CurFile *)jcr->file_list->lookup(fname);
186 memcpy(ret, temp, sizeof(CurFile));
191 Dmsg1(2, "lookup <%s> ok\n", fname);
197 static bool accurate_init(JCR *jcr, int nbfile)
200 jcr->file_list = (htable *)malloc(sizeof(htable));
201 jcr->file_list->init(elt, &elt->link, nbfile);
205 bool accurate_send_deleted_list(JCR *jcr)
209 int stream = STREAM_UNIX_ATTRIBUTES;
211 if (!jcr->accurate || jcr->JobLevel == L_FULL) {
215 if (jcr->file_list == NULL) {
219 ff_pkt = init_find_files();
220 ff_pkt->type = FT_DELETED;
222 foreach_htable (elt, jcr->file_list) {
223 if (!elt->seen) { /* already seen */
224 Dmsg2(1, "deleted fname=%s seen=%i\n", elt->fname, elt->seen);
225 ff_pkt->fname = elt->fname;
226 ff_pkt->statp.st_mtime = elt->mtime;
227 ff_pkt->statp.st_ctime = elt->ctime;
228 encode_and_send_attributes(jcr, ff_pkt, stream);
233 term_find_files(ff_pkt);
235 /* TODO: clean htable when this function is not reached ? */
236 if (jcr->file_list) {
237 jcr->file_list->destroy();
238 free(jcr->file_list);
239 jcr->file_list = NULL;
246 static bool accurate_add_file(JCR *jcr, char *fname, char *lstat)
251 decode_stat(lstat, &statp, &LinkFIc); /* decode catalog stat */
252 elt.ctime = statp.st_ctime;
253 elt.mtime = statp.st_mtime;
257 if (!tchdbputasync(jcr->file_list,
258 fname, strlen(fname)+1,
259 &elt, sizeof(CurFile)))
261 Dmsg1(2, "Can't add <%s> to file_list\n", fname);
262 /* TODO: check error */
266 /* we store CurFile, fname and ctime/mtime in the same chunk */
267 item = (CurFile *)jcr->file_list->hash_malloc(sizeof(CurFile)+strlen(fname)+1);
268 memcpy(item, &elt, sizeof(CurFile));
269 item->fname = (char *)item+sizeof(CurFile);
270 strcpy(item->fname, fname);
271 jcr->file_list->insert(item->fname, item);
274 Dmsg2(2, "add fname=<%s> lstat=%s\n", fname, lstat);
279 * This function is called for each file seen in fileset.
280 * We check in file_list hash if fname have been backuped
281 * the last time. After we can compare Lstat field.
282 * Full Lstat usage have been removed on 6612
284 bool accurate_check_file(JCR *jcr, FF_PKT *ff_pkt)
290 if (!jcr->accurate || jcr->JobLevel == L_FULL) {
296 if (S_ISDIR(ff_pkt->statp.st_mode)) {
297 fname = ff_pkt->link;
299 fname = ff_pkt->fname;
302 if (!accurate_lookup(jcr, fname, &elt)) {
303 Dmsg1(2, "accurate %s (not found)\n", fname);
308 if (elt.seen) { /* file has been seen ? */
309 Dmsg1(2, "accurate %s (already seen)\n", fname);
313 if (elt.mtime != ff_pkt->statp.st_mtime) {
314 Jmsg(jcr, M_SAVED, 0, _("%s st_mtime differs\n"), fname);
316 } else if (elt.ctime != ff_pkt->statp.st_ctime) {
317 Jmsg(jcr, M_SAVED, 0, _("%s st_ctime differs\n"), fname);
322 Dmsg4(1, "%i = %i\t%i = %i\n", elt.mtime, ff_pkt->statp.st_mtime,
323 elt.ctime, ff_pkt->statp.st_ctime);
326 accurate_mark_file_as_seen(jcr, &elt);
327 Dmsg2(2, "accurate %s = %i\n", fname, stat);
330 unstrip_path(ff_pkt);
335 * TODO: use bigbuffer from htable
337 int accurate_cmd(JCR *jcr)
339 BSOCK *dir = jcr->dir_bsock;
343 if (!jcr->accurate || job_canceled(jcr) || jcr->JobLevel==L_FULL) {
347 if (sscanf(dir->msg, "accurate files=%ld", &nb) != 1) {
348 dir->fsend(_("2991 Bad accurate command\n"));
351 Dmsg2(2, "nb=%d msg=%s\n", nb, dir->msg);
353 accurate_init(jcr, nb);
356 * buffer = sizeof(CurFile) + dirmsg
357 * dirmsg = fname + \0 + lstat
359 /* get current files */
360 while (dir->recv() >= 0) {
361 Dmsg1(2, "accurate_cmd fname=%s\n", dir->msg);
362 len = strlen(dir->msg) + 1;
363 if (len < dir->msglen) {
364 accurate_add_file(jcr, dir->msg, dir->msg + len);
369 extern void *start_heap;
371 char b1[50], b2[50], b3[50], b4[50], b5[50];
372 Dmsg5(1," Heap: heap=%s smbytes=%s max_bytes=%s bufs=%s max_bufs=%s\n",
373 edit_uint64_with_commas((char *)sbrk(0)-(char *)start_heap, b1),
374 edit_uint64_with_commas(sm_bytes, b2),
375 edit_uint64_with_commas(sm_max_bytes, b3),
376 edit_uint64_with_commas(sm_buffers, b4),
377 edit_uint64_with_commas(sm_max_buffers, b5));