2 Bacula(R) - The Network Backup Solution
4 Copyright (C) 2000-2015 Kern Sibbald
5 Copyright (C) 2000-2014 Free Software Foundation Europe e.V.
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.
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.
15 This notice must be preserved when any source code is
16 conveyed and/or propagated.
18 Bacula(R) is a registered trademark of Kern Sibbald.
21 * Bacula File Daemon verify.c Verify files.
23 * Kern Sibbald, October MM
30 static int verify_file(JCR *jcr, FF_PKT *ff_pkt, bool);
31 static int read_digest(BFILE *bfd, DIGEST *digest, JCR *jcr);
34 * Find all the requested files and send attributes
38 void do_verify(JCR *jcr)
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);
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");
56 jcr->setJobStatus(JS_Terminated);
60 * Called here by find() for each file.
62 * Find the file, compute the MD5 or SHA1 and send it back to the Director
64 static int verify_file(JCR *jcr, FF_PKT *ff_pkt, bool top_level)
66 char attribs[MAXSTRING];
67 char attribsEx[MAXSTRING];
68 int digest_stream = STREAM_NONE;
70 DIGEST *digest = NULL;
73 if (job_canceled(jcr)) {
78 jcr->num_files_examined++; /* bump total file count */
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);
85 Dmsg1(30, "FT_REGE saving: %s\n", ff_pkt->fname);
88 Dmsg1(30, "FT_REG saving: %s\n", ff_pkt->fname);
91 Dmsg2(30, "FT_LNK saving: %s -> %s\n", ff_pkt->fname, ff_pkt->link);
94 jcr->num_files_examined--; /* correct file count */
95 return 1; /* ignored */
99 Dmsg1(30, "FT_DIR saving: %s\n", ff_pkt->fname);
102 Dmsg1(30, "FT_SPEC saving: %s\n", ff_pkt->fname);
105 Dmsg1(30, "FT_RAW saving: %s\n", ff_pkt->fname);
108 Dmsg1(30, "FT_FIFO saving: %s\n", ff_pkt->fname);
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());
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());
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());
133 Jmsg(jcr, M_SKIPPED, 1, _(" Unchanged file skipped: %s\n"), ff_pkt->fname);
136 Jmsg(jcr, M_SKIPPED, 1, _(" Archive file skipped: %s\n"), ff_pkt->fname);
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 */
143 Jmsg(jcr, M_SKIPPED, 1, _(" File system change prohibited. Directory skipped: %s\n"), ff_pkt->fname);
145 case FT_PLUGIN_CONFIG:
146 case FT_RESTORE_FIRST:
147 return 1; /* silently skip */
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());
156 Jmsg(jcr, M_NOTSAVED, 0, _(" Unknown file type %d: %s\n"), ff_pkt->type, ff_pkt->fname);
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);
166 jcr->JobFiles++; /* increment number of files sent */
167 pm_strcpy(jcr->last_fname, ff_pkt->fname);
171 * Send file attributes to Director
175 * Filename (full path)
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.
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,
194 stat = dir->fsend("%d %d %s %s%c%s%c%c", jcr->JobFiles,
195 STREAM_UNIX_ATTRIBUTES, ff_pkt->VerifyOpts, ff_pkt->fname,
198 Dmsg2(20, "bfiled>bdird: attribs len=%d: msg=%s\n", dir->msglen, dir->msg);
200 Jmsg(jcr, M_FATAL, 0, _("Network error in send to Director: ERR=%s\n"), dir->bstrerror());
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.
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))) {
211 * Create our digest context. If this fails, the digest will be set to NULL
214 if (ff_pkt->flags & FO_MD5) {
215 digest = crypto_digest_new(jcr, CRYPTO_DIGEST_MD5);
216 digest_stream = STREAM_MD5_DIGEST;
218 } else if (ff_pkt->flags & FO_SHA1) {
219 digest = crypto_digest_new(jcr, CRYPTO_DIGEST_SHA1);
220 digest_stream = STREAM_SHA1_DIGEST;
222 } else if (ff_pkt->flags & FO_SHA256) {
223 digest = crypto_digest_new(jcr, CRYPTO_DIGEST_SHA256);
224 digest_stream = STREAM_SHA256_DIGEST;
226 } else if (ff_pkt->flags & FO_SHA512) {
227 digest = crypto_digest_new(jcr, CRYPTO_DIGEST_SHA512);
228 digest_stream = STREAM_SHA512_DIGEST;
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));
237 /* compute MD5 or SHA1 hash */
239 char md[CRYPTO_DIGEST_MAX_SIZE];
244 if (digest_file(jcr, ff_pkt, digest) != 0) {
249 if (crypto_digest_finalize(digest, (uint8_t *)md, &size)) {
251 const char *digest_name;
253 digest_buf = (char *)malloc(BASE64_SIZE(size));
254 digest_name = crypto_digest_name(digest);
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);
270 crypto_digest_free(digest);
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.
279 int digest_file(JCR *jcr, FF_PKT *ff_pkt, DIGEST *digest)
283 Dmsg0(50, "=== digest_file\n");
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;
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());
298 read_digest(&bfd, digest, jcr);
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;
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);
315 read_digest(&bfd, digest, jcr);
318 if (digest && ff_pkt->flags & FO_HFSPLUS) {
319 crypto_digest_update(digest, (uint8_t *)ff_pkt->hfsinfo.fndrinfo, 32);
326 * Read message digest of bfd, updating digest
327 * In case of errors we need the job control record and file name.
329 static int read_digest(BFILE *bfd, DIGEST *digest, JCR *jcr)
331 char buf[DEFAULT_NETWORK_BUFFER_SIZE];
333 int64_t bufsiz = (int64_t)sizeof(buf);
334 FF_PKT *ff_pkt = (FF_PKT *)jcr->ff;
335 uint64_t fileAddr = 0; /* file address */
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;
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);
349 fileAddr += n; /* update file address */
350 /* Skip any block of all zeros */
352 continue; /* skip block of zeros */
356 crypto_digest_update(digest, (uint8_t *)buf, n);
358 /* Can be used by BaseJobs or with accurate, update only for Verify
361 if (jcr->getJobType() == JT_VERIFY) {
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());