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 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.
36 static int dbglvl=200;
38 typedef struct PrivateCurFile {
42 char *fname; /* not stored with tchdb mode */
49 static void realfree(void *p); /* used by tokyo code */
52 * Update hash element seen=1
54 static bool accurate_mark_file_as_seen(JCR *jcr, CurFile *elt)
59 if (!tcadbput(jcr->file_list,
60 elt->fname, strlen(elt->fname)+1,
61 elt, sizeof(CurFile)))
62 { /* TODO: disabling accurate mode ? */
63 Jmsg(jcr, M_ERROR, 1, _("Can't update accurate hash disk\n"));
70 static bool accurate_lookup(JCR *jcr, char *fname, CurFile *ret)
77 elt = (CurFile*)tcadbget(jcr->file_list,
78 fname, strlen(fname)+1, &size);
81 /* TODO: don't malloc/free results */
84 memcpy(ret, elt, sizeof(CurFile));
86 // Dmsg1(dbglvl, "lookup <%s> ok\n", fname);
91 /* Create tokyo dbm hash file
92 * If something goes wrong, we cancel accurate mode.
94 static bool accurate_init(JCR *jcr, int nbfile)
96 jcr->file_list = tcadbnew();
98 // tchdbsetcache(jcr->file_list, 300000);
99 // tchdbtune(jcr->file_list,
100 // nbfile, /* nb bucket 0.5n to 4n */
101 // 6, /* size of element 2^x */
103 // 0); /* options like compression */
105 jcr->hash_name = get_pool_memory(PM_MESSAGE);
106 POOLMEM *temp = get_pool_memory(PM_MESSAGE);
108 if (nbfile > 500000) {
109 make_unique_filename(&jcr->hash_name, jcr->JobId, "accurate");
110 pm_strcat(jcr->hash_name, ".tcb");
111 Mmsg(temp, "%s#bnum=%i#mode=e#opts=l",
112 jcr->hash_name, nbfile*4);
113 Dmsg1(dbglvl, "Doing accurate hash on disk %s\n", jcr->hash_name);
115 Dmsg0(dbglvl, "Doing accurate hash on memory\n");
116 pm_strcpy(jcr->hash_name, "*");
117 pm_strcpy(temp, "*");
120 if(!tcadbopen(jcr->file_list, jcr->hash_name)){
121 Jmsg(jcr, M_ERROR, 1, _("Can't open accurate hash disk\n"));
122 Jmsg(jcr, M_INFO, 1, _("Disabling accurate mode\n"));
123 tcadbdel(jcr->file_list);
124 jcr->file_list = NULL;
125 jcr->accurate = false;
127 free_pool_memory(temp);
128 return jcr->file_list != NULL;
131 /* This function is called at the end of backup
132 * We walk over all hash disk element, and we check
135 bool accurate_send_deleted_list(JCR *jcr)
141 int stream = STREAM_UNIX_ATTRIBUTES;
143 if (!jcr->accurate || jcr->get_JobLevel() == L_FULL) {
147 if (jcr->file_list == NULL) {
151 ff_pkt = init_find_files();
152 ff_pkt->type = FT_DELETED;
154 /* traverse records */
155 tcadbiterinit(jcr->file_list);
156 while((key = tcadbiternext2(jcr->file_list)) != NULL) {
157 elt = (CurFile *) tcadbget(jcr->file_list,
158 key, strlen(key)+1, &size);
161 if (!elt->seen) { /* already seen */
163 ff_pkt->statp.st_mtime = elt->mtime;
164 ff_pkt->statp.st_ctime = elt->ctime;
165 encode_and_send_attributes(jcr, ff_pkt, stream);
169 realfree(key); /* tokyo cabinet have to use real free() */
172 term_find_files(ff_pkt);
174 /* TODO: clean htable when this function is not reached ? */
175 if (jcr->file_list) {
176 if(!tcadbclose(jcr->file_list)){
177 Jmsg(jcr, M_ERROR, 1, _("Can't close accurate hash disk\n"));
180 /* delete the object */
181 tcadbdel(jcr->file_list);
182 if (!bstrcmp(jcr->hash_name, "*")) {
183 unlink(jcr->hash_name);
186 free_pool_memory(jcr->hash_name);
187 jcr->hash_name = NULL;
188 jcr->file_list = NULL;
193 #else /* HTABLE mode */
195 static bool accurate_mark_file_as_seen(JCR *jcr, CurFile *elt)
197 CurFile *temp = (CurFile *)jcr->file_list->lookup(elt->fname);
198 temp->seen = 1; /* records are in memory */
202 static bool accurate_lookup(JCR *jcr, char *fname, CurFile *ret)
207 CurFile *temp = (CurFile *)jcr->file_list->lookup(fname);
209 memcpy(ret, temp, sizeof(CurFile));
211 // Dmsg1(dbglvl, "lookup <%s> ok\n", fname);
217 static bool accurate_init(JCR *jcr, int nbfile)
220 jcr->file_list = (htable *)malloc(sizeof(htable));
221 jcr->file_list->init(elt, &elt->link, nbfile);
225 /* This function is called at the end of backup
226 * We walk over all hash disk element, and we check
229 bool accurate_send_deleted_list(JCR *jcr)
233 int stream = STREAM_UNIX_ATTRIBUTES;
235 if (!jcr->accurate || jcr->get_JobLevel() == L_FULL) {
239 if (jcr->file_list == NULL) {
243 ff_pkt = init_find_files();
244 ff_pkt->type = FT_DELETED;
246 foreach_htable(elt, jcr->file_list) {
247 if (!elt->seen) { /* already seen */
248 Dmsg2(dbglvl, "deleted fname=%s seen=%i\n", elt->fname, elt->seen);
249 ff_pkt->fname = elt->fname;
250 ff_pkt->statp.st_mtime = elt->mtime;
251 ff_pkt->statp.st_ctime = elt->ctime;
252 encode_and_send_attributes(jcr, ff_pkt, stream);
257 term_find_files(ff_pkt);
259 /* TODO: clean htable when this function is not reached ? */
260 if (jcr->file_list) {
261 jcr->file_list->destroy();
262 free(jcr->file_list);
263 jcr->file_list = NULL;
268 #endif /* common code */
270 static bool accurate_add_file(JCR *jcr, char *fname, char *lstat)
276 decode_stat(lstat, &statp, &LinkFIc); /* decode catalog stat */
277 elt.ctime = statp.st_ctime;
278 elt.mtime = statp.st_mtime;
282 if (!tcadbput(jcr->file_list,
283 fname, strlen(fname)+1,
284 &elt, sizeof(CurFile)))
286 Jmsg(jcr, M_ERROR, 1, _("Can't update accurate hash disk ERR=%s\n"));
291 /* we store CurFile, fname and ctime/mtime in the same chunk */
292 item = (CurFile *)jcr->file_list->hash_malloc(sizeof(CurFile)+strlen(fname)+1);
293 memcpy(item, &elt, sizeof(CurFile));
294 item->fname = (char *)item+sizeof(CurFile);
295 strcpy(item->fname, fname);
296 jcr->file_list->insert(item->fname, item);
299 // Dmsg2(dbglvl, "add fname=<%s> lstat=%s\n", fname, lstat);
304 * This function is called for each file seen in fileset.
305 * We check in file_list hash if fname have been backuped
306 * the last time. After we can compare Lstat field.
307 * Full Lstat usage have been removed on 6612
309 bool accurate_check_file(JCR *jcr, FF_PKT *ff_pkt)
315 if (!jcr->accurate || jcr->get_JobLevel() == L_FULL) {
321 if (S_ISDIR(ff_pkt->statp.st_mode)) {
322 fname = ff_pkt->link;
324 fname = ff_pkt->fname;
327 if (!accurate_lookup(jcr, fname, &elt)) {
328 Dmsg1(dbglvl, "accurate %s (not found)\n", fname);
333 if (elt.seen) { /* file has been seen ? */
334 Dmsg1(dbglvl, "accurate %s (already seen)\n", fname);
338 if (elt.mtime != ff_pkt->statp.st_mtime) {
339 Jmsg(jcr, M_SAVED, 0, _("%s st_mtime differs\n"), fname);
341 } else if (elt.ctime != ff_pkt->statp.st_ctime) {
342 Jmsg(jcr, M_SAVED, 0, _("%s st_ctime differs\n"), fname);
346 accurate_mark_file_as_seen(jcr, &elt);
347 Dmsg2(dbglvl, "accurate %s = %i\n", fname, stat);
350 unstrip_path(ff_pkt);
355 * TODO: use big buffer from htable
357 int accurate_cmd(JCR *jcr)
359 BSOCK *dir = jcr->dir_bsock;
363 if (!jcr->accurate || job_canceled(jcr) || jcr->get_JobLevel()==L_FULL) {
367 if (sscanf(dir->msg, "accurate files=%ld", &nb) != 1) {
368 dir->fsend(_("2991 Bad accurate command\n"));
372 accurate_init(jcr, nb);
375 * buffer = sizeof(CurFile) + dirmsg
376 * dirmsg = fname + \0 + lstat
378 /* get current files */
379 while (dir->recv() >= 0) {
380 len = strlen(dir->msg) + 1;
381 if (len < dir->msglen) {
382 accurate_add_file(jcr, dir->msg, dir->msg + len);
387 extern void *start_heap;
389 char b1[50], b2[50], b3[50], b4[50], b5[50];
390 Dmsg5(dbglvl," Heap: heap=%s smbytes=%s max_bytes=%s bufs=%s max_bufs=%s\n",
391 edit_uint64_with_commas((char *)sbrk(0)-(char *)start_heap, b1),
392 edit_uint64_with_commas(sm_bytes, b2),
393 edit_uint64_with_commas(sm_max_bytes, b3),
394 edit_uint64_with_commas(sm_buffers, b4),
395 edit_uint64_with_commas(sm_max_buffers, b5));
404 * Tokyo Cabinet library doesn't use smartalloc by default
405 * results need to be released with real free()
408 void realfree(void *p)