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