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