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 static int dbglvl=200;
38 typedef struct PrivateCurFile {
39 char *fname; /* not stored with tchdb mode */
45 static void realfree(void *p); /* used by tokyo code */
48 * Update hash element seen=1
50 static bool accurate_mark_file_as_seen(JCR *jcr, CurFile *elt)
55 if (!tcadbput(jcr->file_list,
56 elt->fname, strlen(elt->fname)+1,
57 elt, sizeof(CurFile)))
58 { /* TODO: disabling accurate mode ? */
59 Jmsg(jcr, M_ERROR, 1, _("Can't update accurate hash disk\n"));
66 static bool accurate_lookup(JCR *jcr, char *fname, CurFile *ret)
73 elt = (CurFile*)tcadbget(jcr->file_list,
74 fname, strlen(fname)+1, &size);
77 /* TODO: don't malloc/free results */
80 memcpy(ret, elt, sizeof(CurFile));
82 // Dmsg1(dbglvl, "lookup <%s> ok\n", fname);
87 /* Create tokyo dbm hash file
88 * If something goes wrong, we cancel accurate mode.
90 static bool accurate_init(JCR *jcr, int nbfile)
92 jcr->file_list = tcadbnew();
94 // tchdbsetcache(jcr->file_list, 300000);
95 // tchdbtune(jcr->file_list,
96 // nbfile, /* nb bucket 0.5n to 4n */
97 // 6, /* size of element 2^x */
99 // 0); /* options like compression */
101 jcr->hash_name = get_pool_memory(PM_MESSAGE);
102 POOLMEM *temp = get_pool_memory(PM_MESSAGE);
104 if (nbfile > 500000) {
105 make_unique_filename(&jcr->hash_name, jcr->JobId, "accurate");
106 pm_strcat(jcr->hash_name, ".tcb");
107 Mmsg(temp, "%s#bnum=%i#mode=e#opts=l",
108 jcr->hash_name, nbfile*4);
109 Dmsg1(dbglvl, "Doing accurate hash on disk %s\n", jcr->hash_name);
111 Dmsg0(dbglvl, "Doing accurate hash on memory\n");
112 pm_strcpy(jcr->hash_name, "*");
113 pm_strcpy(temp, "*");
116 if(!tcadbopen(jcr->file_list, jcr->hash_name)){
117 Jmsg(jcr, M_ERROR, 1, _("Can't open accurate hash disk\n"));
118 Jmsg(jcr, M_INFO, 1, _("Disabling accurate mode\n"));
119 tcadbdel(jcr->file_list);
120 jcr->file_list = NULL;
121 jcr->accurate = false;
123 free_pool_memory(temp);
124 return jcr->file_list != NULL;
127 /* This function is called at the end of backup
128 * We walk over all hash disk element, and we check
131 bool accurate_send_deleted_list(JCR *jcr)
137 int stream = STREAM_UNIX_ATTRIBUTES;
139 if (!jcr->accurate || jcr->JobLevel == L_FULL) {
143 if (jcr->file_list == NULL) {
147 ff_pkt = init_find_files();
148 ff_pkt->type = FT_DELETED;
150 /* traverse records */
151 tcadbiterinit(jcr->file_list);
152 while((key = tcadbiternext2(jcr->file_list)) != NULL) {
153 elt = (CurFile *) tcadbget(jcr->file_list,
154 key, strlen(key)+1, &size);
157 if (!elt->seen) { /* already seen */
159 ff_pkt->statp.st_mtime = elt->mtime;
160 ff_pkt->statp.st_ctime = elt->ctime;
161 encode_and_send_attributes(jcr, ff_pkt, stream);
165 realfree(key); /* tokyo cabinet have to use real free() */
168 term_find_files(ff_pkt);
170 /* TODO: clean htable when this function is not reached ? */
171 if (jcr->file_list) {
172 if(!tcadbclose(jcr->file_list)){
173 Jmsg(jcr, M_ERROR, 1, _("Can't close accurate hash disk\n"));
176 /* delete the object */
177 tcadbdel(jcr->file_list);
178 if (!bstrcmp(jcr->hash_name, "*")) {
179 unlink(jcr->hash_name);
182 free_pool_memory(jcr->hash_name);
183 jcr->hash_name = NULL;
184 jcr->file_list = NULL;
189 static bool accurate_add_file(JCR *jcr, char *fname, char *lstat)
195 decode_stat(lstat, &statp, &LinkFIc); /* decode catalog stat */
196 elt.ctime = statp.st_ctime;
197 elt.mtime = statp.st_mtime;
200 if (!tcadbput(jcr->file_list,
201 fname, strlen(fname)+1,
202 &elt, sizeof(CurFile)))
204 Jmsg(jcr, M_ERROR, 1, _("Can't update accurate hash disk ERR=%s\n"));
208 // Dmsg2(dbglvl, "add fname=<%s> lstat=%s\n", fname, lstat);
213 * This function is called for each file seen in fileset.
214 * We check in file_list hash if fname have been backuped
215 * the last time. After we can compare Lstat field.
216 * Full Lstat usage have been removed on 6612
218 bool accurate_check_file(JCR *jcr, FF_PKT *ff_pkt)
224 if (!jcr->accurate || jcr->JobLevel == L_FULL) {
230 if (S_ISDIR(ff_pkt->statp.st_mode)) {
231 fname = ff_pkt->link;
233 fname = ff_pkt->fname;
236 if (!accurate_lookup(jcr, fname, &elt)) {
237 Dmsg1(dbglvl, "accurate %s (not found)\n", fname);
242 if (elt.seen) { /* file has been seen ? */
243 Dmsg1(dbglvl, "accurate %s (already seen)\n", fname);
247 if (elt.mtime != ff_pkt->statp.st_mtime) {
248 Jmsg(jcr, M_SAVED, 0, _("%s st_mtime differs\n"), fname);
250 } else if (elt.ctime != ff_pkt->statp.st_ctime) {
251 Jmsg(jcr, M_SAVED, 0, _("%s st_ctime differs\n"), fname);
255 accurate_mark_file_as_seen(jcr, &elt);
256 Dmsg2(dbglvl, "accurate %s = %i\n", fname, stat);
259 unstrip_path(ff_pkt);
264 * TODO: use bigbuffer from htable
266 int accurate_cmd(JCR *jcr)
268 BSOCK *dir = jcr->dir_bsock;
272 if (!jcr->accurate || job_canceled(jcr) || jcr->JobLevel==L_FULL) {
276 if (sscanf(dir->msg, "accurate files=%ld", &nb) != 1) {
277 dir->fsend(_("2991 Bad accurate command\n"));
281 accurate_init(jcr, nb);
284 * buffer = sizeof(CurFile) + dirmsg
285 * dirmsg = fname + \0 + lstat
287 /* get current files */
288 while (dir->recv() >= 0) {
289 len = strlen(dir->msg) + 1;
290 if (len < dir->msglen) {
291 accurate_add_file(jcr, dir->msg, dir->msg + len);
296 extern void *start_heap;
298 char b1[50], b2[50], b3[50], b4[50], b5[50];
299 Dmsg5(dbglvl," Heap: heap=%s smbytes=%s max_bytes=%s bufs=%s max_bufs=%s\n",
300 edit_uint64_with_commas((char *)sbrk(0)-(char *)start_heap, b1),
301 edit_uint64_with_commas(sm_bytes, b2),
302 edit_uint64_with_commas(sm_max_bytes, b3),
303 edit_uint64_with_commas(sm_buffers, b4),
304 edit_uint64_with_commas(sm_max_buffers, b5));
312 * Tokyo Cabinet library doesn't use smartalloc by default
313 * results need to be released with real free()
316 void realfree(void *p)