2 Bacula(R) - The Network Backup Solution
4 Copyright (C) 2000-2015 Kern Sibbald
6 The original author of Bacula is Kern Sibbald, with contributions
7 from many others, a complete list can be found in the file AUTHORS.
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.
14 This notice must be preserved when any source code is
15 conveyed and/or propagated.
17 Bacula(R) is a registered trademark of Kern Sibbald.
20 * Bacula File Daemon verify.c Verify files.
22 * Kern Sibbald, October MM
29 static int verify_file(JCR *jcr, FF_PKT *ff_pkt, bool);
30 static int read_digest(BFILE *bfd, DIGEST *digest, JCR *jcr);
33 * Find all the requested files and send attributes
37 void do_verify(JCR *jcr)
39 jcr->setJobStatus(JS_Running);
40 jcr->buf_size = DEFAULT_NETWORK_BUFFER_SIZE;
41 if ((jcr->big_buf = (char *) malloc(jcr->buf_size)) == NULL) {
42 Jmsg1(jcr, M_ABORT, 0, _("Cannot malloc %d network read buffer\n"),
43 DEFAULT_NETWORK_BUFFER_SIZE);
45 set_find_options((FF_PKT *)jcr->ff, jcr->incremental, jcr->mtime);
46 Dmsg0(10, "Start find files\n");
47 /* Subroutine verify_file() is called for each file */
48 find_files(jcr, (FF_PKT *)jcr->ff, verify_file, NULL);
49 Dmsg0(10, "End find files\n");
55 jcr->setJobStatus(JS_Terminated);
59 * Called here by find() for each file.
61 * Find the file, compute the MD5 or SHA1 and send it back to the Director
63 static int verify_file(JCR *jcr, FF_PKT *ff_pkt, bool top_level)
65 char attribs[MAXSTRING];
66 char attribsEx[MAXSTRING];
67 int digest_stream = STREAM_NONE;
69 DIGEST *digest = NULL;
72 if (job_canceled(jcr)) {
77 jcr->num_files_examined++; /* bump total file count */
79 switch (ff_pkt->type) {
80 case FT_LNKSAVED: /* Hard linked, file already saved */
81 Dmsg2(30, "FT_LNKSAVED saving: %s => %s\n", ff_pkt->fname, ff_pkt->link);
84 Dmsg1(30, "FT_REGE saving: %s\n", ff_pkt->fname);
87 Dmsg1(30, "FT_REG saving: %s\n", ff_pkt->fname);
90 Dmsg2(30, "FT_LNK saving: %s -> %s\n", ff_pkt->fname, ff_pkt->link);
93 jcr->num_files_examined--; /* correct file count */
94 return 1; /* ignored */
98 Dmsg1(30, "FT_DIR saving: %s\n", ff_pkt->fname);
101 Dmsg1(30, "FT_SPEC saving: %s\n", ff_pkt->fname);
104 Dmsg1(30, "FT_RAW saving: %s\n", ff_pkt->fname);
107 Dmsg1(30, "FT_FIFO saving: %s\n", ff_pkt->fname);
111 be.set_errno(ff_pkt->ff_errno);
112 Jmsg(jcr, M_NOTSAVED, 1, _(" Could not access %s: ERR=%s\n"), ff_pkt->fname, be.bstrerror());
118 be.set_errno(ff_pkt->ff_errno);
119 Jmsg(jcr, M_NOTSAVED, 1, _(" Could not follow link %s: ERR=%s\n"), ff_pkt->fname, be.bstrerror());
125 be.set_errno(ff_pkt->ff_errno);
126 Jmsg(jcr, M_NOTSAVED, 1, _(" Could not stat %s: ERR=%s\n"), ff_pkt->fname, be.bstrerror());
132 Jmsg(jcr, M_SKIPPED, 1, _(" Unchanged file skipped: %s\n"), ff_pkt->fname);
135 Jmsg(jcr, M_SKIPPED, 1, _(" Archive file skipped: %s\n"), ff_pkt->fname);
138 Jmsg(jcr, M_SKIPPED, 1, _(" Recursion turned off. Directory skipped: %s\n"), ff_pkt->fname);
139 ff_pkt->type = FT_DIREND; /* directory entry was backed up */
142 Jmsg(jcr, M_SKIPPED, 1, _(" File system change prohibited. Directory skipped: %s\n"), ff_pkt->fname);
144 case FT_PLUGIN_CONFIG:
145 case FT_RESTORE_FIRST:
146 return 1; /* silently skip */
149 be.set_errno(ff_pkt->ff_errno);
150 Jmsg(jcr, M_NOTSAVED, 1, _(" Could not open directory %s: ERR=%s\n"), ff_pkt->fname, be.bstrerror());
155 Jmsg(jcr, M_NOTSAVED, 0, _(" Unknown file type %d: %s\n"), ff_pkt->type, ff_pkt->fname);
160 /* Encode attributes and possibly extend them */
161 encode_stat(attribs, &ff_pkt->statp, sizeof(ff_pkt->statp), ff_pkt->LinkFI, 0);
162 encode_attribsEx(jcr, attribsEx, ff_pkt);
165 jcr->JobFiles++; /* increment number of files sent */
166 pm_strcpy(jcr->last_fname, ff_pkt->fname);
170 * Send file attributes to Director
174 * Filename (full path)
176 * Link name (if type==FT_LNK)
177 * For a directory, link is the same as fname, but with trailing
178 * slash. For a linked file, link is the link.
180 /* Send file attributes to Director (note different format than for Storage) */
181 Dmsg2(400, "send ATTR inx=%d fname=%s\n", jcr->JobFiles, ff_pkt->fname);
182 if (ff_pkt->type == FT_LNK || ff_pkt->type == FT_LNKSAVED) {
183 stat = dir->fsend("%d %d %s %s%c%s%c%s%c", jcr->JobFiles,
184 STREAM_UNIX_ATTRIBUTES, ff_pkt->VerifyOpts, ff_pkt->fname,
185 0, attribs, 0, ff_pkt->link, 0);
186 } else if (ff_pkt->type == FT_DIREND || ff_pkt->type == FT_REPARSE ||
187 ff_pkt->type == FT_JUNCTION) {
188 /* Here link is the canonical filename (i.e. with trailing slash) */
189 stat = dir->fsend("%d %d %s %s%c%s%c%c", jcr->JobFiles,
190 STREAM_UNIX_ATTRIBUTES, ff_pkt->VerifyOpts, ff_pkt->link,
193 stat = dir->fsend("%d %d %s %s%c%s%c%c", jcr->JobFiles,
194 STREAM_UNIX_ATTRIBUTES, ff_pkt->VerifyOpts, ff_pkt->fname,
197 Dmsg2(20, "bfiled>bdird: attribs len=%d: msg=%s\n", dir->msglen, dir->msg);
199 Jmsg(jcr, M_FATAL, 0, _("Network error in send to Director: ERR=%s\n"), dir->bstrerror());
204 * The remainder of the function is all about getting the checksum.
205 * First we initialise, then we read files, other streams and Finder Info.
207 if (ff_pkt->type != FT_LNKSAVED && (S_ISREG(ff_pkt->statp.st_mode) &&
208 ff_pkt->flags & (FO_MD5|FO_SHA1|FO_SHA256|FO_SHA512))) {
210 * Create our digest context. If this fails, the digest will be set to NULL
213 if (ff_pkt->flags & FO_MD5) {
214 digest = crypto_digest_new(jcr, CRYPTO_DIGEST_MD5);
215 digest_stream = STREAM_MD5_DIGEST;
217 } else if (ff_pkt->flags & FO_SHA1) {
218 digest = crypto_digest_new(jcr, CRYPTO_DIGEST_SHA1);
219 digest_stream = STREAM_SHA1_DIGEST;
221 } else if (ff_pkt->flags & FO_SHA256) {
222 digest = crypto_digest_new(jcr, CRYPTO_DIGEST_SHA256);
223 digest_stream = STREAM_SHA256_DIGEST;
225 } else if (ff_pkt->flags & FO_SHA512) {
226 digest = crypto_digest_new(jcr, CRYPTO_DIGEST_SHA512);
227 digest_stream = STREAM_SHA512_DIGEST;
230 /* Did digest initialization fail? */
231 if (digest_stream != STREAM_NONE && digest == NULL) {
232 Jmsg(jcr, M_WARNING, 0, _("%s digest initialization failed\n"),
233 stream_to_ascii(digest_stream));
236 /* compute MD5 or SHA1 hash */
238 char md[CRYPTO_DIGEST_MAX_SIZE];
243 if (digest_file(jcr, ff_pkt, digest) != 0) {
248 if (crypto_digest_finalize(digest, (uint8_t *)md, &size)) {
250 const char *digest_name;
252 digest_buf = (char *)malloc(BASE64_SIZE(size));
253 digest_name = crypto_digest_name(digest);
255 bin_to_base64(digest_buf, BASE64_SIZE(size), md, size, true);
256 Dmsg3(400, "send inx=%d %s=%s\n", jcr->JobFiles, digest_name, digest_buf);
257 dir->fsend("%d %d %s *%s-%d*", jcr->JobFiles, digest_stream, digest_buf,
258 digest_name, jcr->JobFiles);
259 Dmsg3(20, "bfiled>bdird: %s len=%d: msg=%s\n", digest_name,
260 dir->msglen, dir->msg);
269 crypto_digest_free(digest);
275 * Compute message digest for the file specified by ff_pkt.
276 * In case of errors we need the job control record and file name.
278 int digest_file(JCR *jcr, FF_PKT *ff_pkt, DIGEST *digest)
282 Dmsg0(50, "=== digest_file\n");
285 if (ff_pkt->statp.st_size > 0 || ff_pkt->type == FT_RAW
286 || ff_pkt->type == FT_FIFO) {
287 int noatime = ff_pkt->flags & FO_NOATIME ? O_NOATIME : 0;
288 if ((bopen(&bfd, ff_pkt->fname, O_RDONLY | O_BINARY | noatime, 0)) < 0) {
289 ff_pkt->ff_errno = errno;
291 be.set_errno(bfd.berrno);
292 Dmsg2(100, "Cannot open %s: ERR=%s\n", ff_pkt->fname, be.bstrerror());
293 Jmsg(jcr, M_ERROR, 1, _(" Cannot open %s: ERR=%s.\n"),
294 ff_pkt->fname, be.bstrerror());
297 read_digest(&bfd, digest, jcr);
301 #ifdef HAVE_DARWIN_OS
302 /* Open resource fork if necessary */
303 if (ff_pkt->flags & FO_HFSPLUS && ff_pkt->hfsinfo.rsrclength > 0) {
304 if (bopen_rsrc(&bfd, ff_pkt->fname, O_RDONLY | O_BINARY, 0) < 0) {
305 ff_pkt->ff_errno = errno;
307 Jmsg(jcr, M_ERROR, -1, _(" Cannot open resource fork for %s: ERR=%s.\n"),
308 ff_pkt->fname, be.bstrerror());
309 if (is_bopen(&ff_pkt->bfd)) {
310 bclose(&ff_pkt->bfd);
314 read_digest(&bfd, digest, jcr);
317 if (digest && ff_pkt->flags & FO_HFSPLUS) {
318 crypto_digest_update(digest, (uint8_t *)ff_pkt->hfsinfo.fndrinfo, 32);
325 * Read message digest of bfd, updating digest
326 * In case of errors we need the job control record and file name.
328 static int read_digest(BFILE *bfd, DIGEST *digest, JCR *jcr)
330 char buf[DEFAULT_NETWORK_BUFFER_SIZE];
332 int64_t bufsiz = (int64_t)sizeof(buf);
333 FF_PKT *ff_pkt = (FF_PKT *)jcr->ff;
334 uint64_t fileAddr = 0; /* file address */
337 Dmsg0(50, "=== read_digest\n");
338 while ((n=bread(bfd, buf, bufsiz)) > 0) {
339 /* Check for sparse blocks */
340 if (ff_pkt->flags & FO_SPARSE) {
341 bool allZeros = false;
343 fileAddr+n < (uint64_t)ff_pkt->statp.st_size) ||
344 ((ff_pkt->type == FT_RAW || ff_pkt->type == FT_FIFO) &&
345 (uint64_t)ff_pkt->statp.st_size == 0)) {
346 allZeros = is_buf_zero(buf, bufsiz);
348 fileAddr += n; /* update file address */
349 /* Skip any block of all zeros */
351 continue; /* skip block of zeros */
355 crypto_digest_update(digest, (uint8_t *)buf, n);
357 /* Can be used by BaseJobs or with accurate, update only for Verify
360 if (jcr->getJobType() == JT_VERIFY) {
367 be.set_errno(bfd->berrno);
368 Dmsg2(100, "Error reading file %s: ERR=%s\n", jcr->last_fname, be.bstrerror());
369 Jmsg(jcr, M_ERROR, 1, _("Error reading file %s: ERR=%s\n"),
370 jcr->last_fname, be.bstrerror());