]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/filed/verify.c
86403d533f7c2294a59fb952b162d7092bbd4b36
[bacula/bacula] / bacula / src / filed / verify.c
1 /*
2    Bacula® - The Network Backup Solution
3
4    Copyright (C) 2000-2007 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 plus additions
11    that are listed 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 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.
27 */
28 /*
29  *  Bacula File Daemon  verify.c  Verify files.
30  *
31  *    Kern Sibbald, October MM
32  *
33  *   Version $Id$
34  *
35  */
36
37 #include "bacula.h"
38 #include "filed.h"
39
40 static int verify_file(FF_PKT *ff_pkt, void *my_pkt, bool);
41 static int read_digest(BFILE *bfd, DIGEST *digest, JCR *jcr);
42
43 /*
44  * Find all the requested files and send attributes
45  * to the Director.
46  *
47  */
48 void do_verify(JCR *jcr)
49 {
50    set_jcr_job_status(jcr, JS_Running);
51    jcr->buf_size = DEFAULT_NETWORK_BUFFER_SIZE;
52    if ((jcr->big_buf = (char *) malloc(jcr->buf_size)) == NULL) {
53       Jmsg1(jcr, M_ABORT, 0, _("Cannot malloc %d network read buffer\n"),
54          DEFAULT_NETWORK_BUFFER_SIZE);
55    }
56    set_find_options((FF_PKT *)jcr->ff, jcr->incremental, jcr->mtime);
57    Dmsg0(10, "Start find files\n");
58    /* Subroutine verify_file() is called for each file */
59    find_files(jcr, (FF_PKT *)jcr->ff, verify_file, (void *)jcr);
60    Dmsg0(10, "End find files\n");
61
62    if (jcr->big_buf) {
63       free(jcr->big_buf);
64       jcr->big_buf = NULL;
65    }
66    set_jcr_job_status(jcr, JS_Terminated);
67 }
68
69 /*
70  * Called here by find() for each file.
71  *
72  *  Find the file, compute the MD5 or SHA1 and send it back to the Director
73  */
74 static int verify_file(FF_PKT *ff_pkt, void *pkt, bool top_level)
75 {
76    char attribs[MAXSTRING];
77    char attribsEx[MAXSTRING];
78    int digest_stream = STREAM_NONE;
79    int stat;
80    DIGEST *digest = NULL;
81    BSOCK *dir;
82    JCR *jcr = (JCR *)pkt;
83
84    if (job_canceled(jcr)) {
85       return 0;
86    }
87
88    dir = jcr->dir_bsock;
89    jcr->num_files_examined++;         /* bump total file count */
90
91    switch (ff_pkt->type) {
92    case FT_LNKSAVED:                  /* Hard linked, file already saved */
93       Dmsg2(30, "FT_LNKSAVED saving: %s => %s\n", ff_pkt->fname, ff_pkt->link);
94       break;
95    case FT_REGE:
96       Dmsg1(30, "FT_REGE saving: %s\n", ff_pkt->fname);
97       break;
98    case FT_REG:
99       Dmsg1(30, "FT_REG saving: %s\n", ff_pkt->fname);
100       break;
101    case FT_LNK:
102       Dmsg2(30, "FT_LNK saving: %s -> %s\n", ff_pkt->fname, ff_pkt->link);
103       break;
104    case FT_DIRBEGIN:
105       jcr->num_files_examined--;      /* correct file count */
106       return 1;                       /* ignored */
107    case FT_DIREND:
108       Dmsg1(30, "FT_DIR saving: %s\n", ff_pkt->fname);
109       break;
110    case FT_SPEC:
111       Dmsg1(30, "FT_SPEC saving: %s\n", ff_pkt->fname);
112       break;
113    case FT_RAW:
114       Dmsg1(30, "FT_RAW saving: %s\n", ff_pkt->fname);
115       break;
116    case FT_FIFO:
117       Dmsg1(30, "FT_FIFO saving: %s\n", ff_pkt->fname);
118       break;
119    case FT_NOACCESS: {
120       berrno be;
121       be.set_errno(ff_pkt->ff_errno);
122       Jmsg(jcr, M_NOTSAVED, 1, _("     Could not access %s: ERR=%s\n"), ff_pkt->fname, be.strerror());
123       jcr->Errors++;
124       return 1;
125    }
126    case FT_NOFOLLOW: {
127       berrno be;
128       be.set_errno(ff_pkt->ff_errno);
129       Jmsg(jcr, M_NOTSAVED, 1, _("     Could not follow link %s: ERR=%s\n"), ff_pkt->fname, be.strerror());
130       jcr->Errors++;
131       return 1;
132    }
133    case FT_NOSTAT: {
134       berrno be;
135       be.set_errno(ff_pkt->ff_errno);
136       Jmsg(jcr, M_NOTSAVED, 1, _("     Could not stat %s: ERR=%s\n"), ff_pkt->fname, be.strerror());
137       jcr->Errors++;
138       return 1;
139    }
140    case FT_DIRNOCHG:
141    case FT_NOCHG:
142       Jmsg(jcr, M_SKIPPED, 1, _("     Unchanged file skipped: %s\n"), ff_pkt->fname);
143       return 1;
144    case FT_ISARCH:
145       Jmsg(jcr, M_SKIPPED, 1, _("     Archive file skipped: %s\n"), ff_pkt->fname);
146       return 1;
147    case FT_NORECURSE:
148       Jmsg(jcr, M_SKIPPED, 1, _("     Recursion turned off. Directory skipped: %s\n"), ff_pkt->fname);
149       ff_pkt->type = FT_DIREND;     /* directory entry was backed up */
150       break;
151    case FT_NOFSCHG:
152       Jmsg(jcr, M_SKIPPED, 1, _("     File system change prohibited. Directory skipped: %s\n"), ff_pkt->fname);
153       return 1;
154    case FT_NOOPEN: {
155       berrno be;
156       be.set_errno(ff_pkt->ff_errno);
157       Jmsg(jcr, M_NOTSAVED, 1, _("     Could not open directory %s: ERR=%s\n"), ff_pkt->fname, be.strerror());
158       jcr->Errors++;
159       return 1;
160    }
161    default:
162       Jmsg(jcr, M_NOTSAVED, 0, _("     Unknown file type %d: %s\n"), ff_pkt->type, ff_pkt->fname);
163       jcr->Errors++;
164       return 1;
165    }
166
167    /* Encode attributes and possibly extend them */
168    encode_stat(attribs, ff_pkt, 0);
169    encode_attribsEx(jcr, attribsEx, ff_pkt);
170
171    jcr->lock();
172    jcr->JobFiles++;                  /* increment number of files sent */
173    pm_strcpy(jcr->last_fname, ff_pkt->fname);
174    jcr->unlock();
175
176    /*
177     * Send file attributes to Director
178     *   File_index
179     *   Stream
180     *   Verify Options
181     *   Filename (full path)
182     *   Encoded attributes
183     *   Link name (if type==FT_LNK)
184     * For a directory, link is the same as fname, but with trailing
185     * slash. For a linked file, link is the link.
186     */
187    /* Send file attributes to Director (note different format than for Storage) */
188    Dmsg2(400, "send ATTR inx=%d fname=%s\n", jcr->JobFiles, ff_pkt->fname);
189    if (ff_pkt->type == FT_LNK || ff_pkt->type == FT_LNKSAVED) {
190       stat = bnet_fsend(dir, "%d %d %s %s%c%s%c%s%c", jcr->JobFiles,
191             STREAM_UNIX_ATTRIBUTES, ff_pkt->VerifyOpts, ff_pkt->fname,
192             0, attribs, 0, ff_pkt->link, 0);
193    } else if (ff_pkt->type == FT_DIREND) {
194          /* Here link is the canonical filename (i.e. with trailing slash) */
195          stat = bnet_fsend(dir,"%d %d %s %s%c%s%c%c", jcr->JobFiles,
196                STREAM_UNIX_ATTRIBUTES, ff_pkt->VerifyOpts, ff_pkt->link,
197                0, attribs, 0, 0);
198    } else {
199       stat = bnet_fsend(dir,"%d %d %s %s%c%s%c%c", jcr->JobFiles,
200             STREAM_UNIX_ATTRIBUTES, ff_pkt->VerifyOpts, ff_pkt->fname,
201             0, attribs, 0, 0);
202    }
203    Dmsg2(20, "bfiled>bdird: attribs len=%d: msg=%s\n", dir->msglen, dir->msg);
204    if (!stat) {
205       Jmsg(jcr, M_FATAL, 0, _("Network error in send to Director: ERR=%s\n"), bnet_strerror(dir));
206       return 0;
207    }
208
209    /*
210     * The remainder of the function is all about getting the checksum.
211     * First we initialise, then we read files, other streams and Finder Info.
212     */
213    if (ff_pkt->type != FT_LNKSAVED && (S_ISREG(ff_pkt->statp.st_mode) &&
214             ff_pkt->flags & (FO_MD5|FO_SHA1|FO_SHA256|FO_SHA512))) {
215       /*
216        * Create our digest context. If this fails, the digest will be set to NULL
217        * and not used.
218        */
219       if (ff_pkt->flags & FO_MD5) {
220          digest = crypto_digest_new(CRYPTO_DIGEST_MD5);
221          digest_stream = STREAM_MD5_DIGEST;
222
223       } else if (ff_pkt->flags & FO_SHA1) {
224          digest = crypto_digest_new(CRYPTO_DIGEST_SHA1);
225          digest_stream = STREAM_SHA1_DIGEST;
226
227       } else if (ff_pkt->flags & FO_SHA256) {
228          digest = crypto_digest_new(CRYPTO_DIGEST_SHA256);
229          digest_stream = STREAM_SHA256_DIGEST;
230
231       } else if (ff_pkt->flags & FO_SHA512) {
232          digest = crypto_digest_new(CRYPTO_DIGEST_SHA512);
233          digest_stream = STREAM_SHA512_DIGEST;
234       }
235
236       /* Did digest initialization fail? */
237       if (digest_stream != STREAM_NONE && digest == NULL) {
238          Jmsg(jcr, M_WARNING, 0, _("%s digest initialization failed\n"),
239               stream_to_ascii(digest_stream));
240       }
241
242       /* compute MD5 or SHA1 hash */
243       if (digest) {
244          char md[CRYPTO_DIGEST_MAX_SIZE];
245          uint32_t size;
246
247          size = sizeof(md);
248          
249          if (digest_file(jcr, ff_pkt, digest) != 0) {
250             jcr->Errors++;
251             return 1;
252          }
253
254          if (crypto_digest_finalize(digest, (uint8_t *)md, &size)) {
255             char *digest_buf;
256             const char *digest_name;
257             
258             digest_buf = (char *)malloc(BASE64_SIZE(size));
259             digest_name = crypto_digest_name(digest);
260
261             bin_to_base64(digest_buf, BASE64_SIZE(size), md, size, true);
262             Dmsg3(400, "send inx=%d %s=%s\n", jcr->JobFiles, digest_name, digest_buf);
263             bnet_fsend(dir, "%d %d %s *%s-%d*", jcr->JobFiles, digest_stream, digest_buf,
264                        digest_name, jcr->JobFiles);
265             Dmsg3(20, "bfiled>bdird: %s len=%d: msg=%s\n", digest_name,
266             dir->msglen, dir->msg);
267
268             free(digest_buf);
269          }
270
271          crypto_digest_free(digest);
272       }
273    }
274
275    return 1;
276 }
277
278 /*
279  * Compute message digest for the file specified by ff_pkt.
280  * In case of errors we need the job control record and file name.
281  */
282 int digest_file(JCR *jcr, FF_PKT *ff_pkt, DIGEST *digest)
283 {
284    BFILE bfd;
285
286    binit(&bfd);
287
288    if (ff_pkt->statp.st_size > 0 || ff_pkt->type == FT_RAW
289          || ff_pkt->type == FT_FIFO) {
290       int noatime = ff_pkt->flags & FO_NOATIME ? O_NOATIME : 0;
291       if ((bopen(&bfd, ff_pkt->fname, O_RDONLY | O_BINARY | noatime, 0)) < 0) {
292          ff_pkt->ff_errno = errno;
293          berrno be;
294          be.set_errno(bfd.berrno);
295          Jmsg(jcr, M_NOTSAVED, 1, _("     Cannot open %s: ERR=%s.\n"),
296                ff_pkt->fname, be.strerror());
297          return 1;
298       }
299       read_digest(&bfd, digest, jcr);
300       bclose(&bfd);
301    }
302
303 #ifdef HAVE_DARWIN_OS
304       /* Open resource fork if necessary */
305    if (ff_pkt->flags & FO_HFSPLUS && ff_pkt->hfsinfo.rsrclength > 0) {
306       if (bopen_rsrc(&bfd, ff_pkt->fname, O_RDONLY | O_BINARY, 0) < 0) {
307          ff_pkt->ff_errno = errno;
308          berrno be;
309          Jmsg(jcr, M_NOTSAVED, -1, _("     Cannot open resource fork for %s: ERR=%s.\n"),
310                ff_pkt->fname, be.strerror());
311          if (is_bopen(&ff_pkt->bfd)) {
312             bclose(&ff_pkt->bfd);
313          }
314          return 1;
315       }
316       read_digest(&bfd, digest, jcr);
317       bclose(&bfd);
318    }
319
320    if (digest && ff_pkt->flags & FO_HFSPLUS) {
321       crypto_digest_update(digest, (uint8_t *)ff_pkt->hfsinfo.fndrinfo, 32);
322    }
323 #endif
324
325    return 0;
326 }
327
328 /*
329  * Read message digest of bfd, updating digest
330  * In case of errors we need the job control record and file name.
331  */
332 int read_digest(BFILE *bfd, DIGEST *digest, JCR *jcr)
333 {
334    char buf[DEFAULT_NETWORK_BUFFER_SIZE];
335    int64_t n;
336
337    while ((n=bread(bfd, buf, sizeof(buf))) > 0) {
338       crypto_digest_update(digest, (uint8_t *)buf, n);
339       jcr->JobBytes += n;
340       jcr->ReadBytes += n;
341    }
342    if (n < 0) {
343       berrno be;
344       be.set_errno(bfd->berrno);
345       Jmsg(jcr, M_ERROR, 1, _("Error reading file %s: ERR=%s\n"),
346             jcr->last_fname, be.strerror());
347       jcr->Errors++;
348       return -1;
349    }
350    return 0;
351 }