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