2 Bacula® - The Network Backup Solution
4 Copyright (C) 2000-2011 Free Software Foundation Europe e.V.
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 three of the GNU Affero General Public
10 License as published by the Free Software Foundation and included
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.
18 You should have received a copy of the GNU Affero 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
23 Bacula® is a registered trademark of Kern Sibbald.
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.
29 * Bacula File Daemon verify.c Verify files.
31 * Kern Sibbald, October MM
39 const bool have_darwin_os = true;
41 const bool have_darwin_os = false;
44 static int verify_file(JCR *jcr, FF_PKT *ff_pkt, bool);
45 static int read_digest(BFILE *bfd, DIGEST *digest, JCR *jcr);
48 * Find all the requested files and send attributes
52 void do_verify(JCR *jcr)
54 jcr->setJobStatus(JS_Running);
55 jcr->buf_size = DEFAULT_NETWORK_BUFFER_SIZE;
56 if ((jcr->big_buf = (char *) malloc(jcr->buf_size)) == NULL) {
57 Jmsg1(jcr, M_ABORT, 0, _("Cannot malloc %d network read buffer\n"),
58 DEFAULT_NETWORK_BUFFER_SIZE);
60 set_find_options((FF_PKT *)jcr->ff, jcr->incremental, jcr->mtime);
61 Dmsg0(10, "Start find files\n");
62 /* Subroutine verify_file() is called for each file */
63 find_files(jcr, (FF_PKT *)jcr->ff, verify_file, NULL);
64 Dmsg0(10, "End find files\n");
70 jcr->setJobStatus(JS_Terminated);
74 * Called here by find() for each file.
76 * Find the file, compute the MD5 or SHA1 and send it back to the Director
78 static int verify_file(JCR *jcr, FF_PKT *ff_pkt, bool top_level)
80 char attribs[MAXSTRING];
81 char attribsEx[MAXSTRING];
82 int digest_stream = STREAM_NONE;
84 DIGEST *digest = NULL;
87 if (job_canceled(jcr)) {
92 jcr->num_files_examined++; /* bump total file count */
94 switch (ff_pkt->type) {
95 case FT_LNKSAVED: /* Hard linked, file already saved */
96 Dmsg2(30, "FT_LNKSAVED saving: %s => %s\n", ff_pkt->fname, ff_pkt->link);
99 Dmsg1(30, "FT_REGE saving: %s\n", ff_pkt->fname);
102 Dmsg1(30, "FT_REG saving: %s\n", ff_pkt->fname);
105 Dmsg2(30, "FT_LNK saving: %s -> %s\n", ff_pkt->fname, ff_pkt->link);
108 jcr->num_files_examined--; /* correct file count */
109 return 1; /* ignored */
113 Dmsg1(30, "FT_DIR saving: %s\n", ff_pkt->fname);
116 Dmsg1(30, "FT_SPEC saving: %s\n", ff_pkt->fname);
119 Dmsg1(30, "FT_RAW saving: %s\n", ff_pkt->fname);
122 Dmsg1(30, "FT_FIFO saving: %s\n", ff_pkt->fname);
126 be.set_errno(ff_pkt->ff_errno);
127 Jmsg(jcr, M_NOTSAVED, 1, _(" Could not access %s: ERR=%s\n"), ff_pkt->fname, be.bstrerror());
133 be.set_errno(ff_pkt->ff_errno);
134 Jmsg(jcr, M_NOTSAVED, 1, _(" Could not follow link %s: ERR=%s\n"), ff_pkt->fname, be.bstrerror());
140 be.set_errno(ff_pkt->ff_errno);
141 Jmsg(jcr, M_NOTSAVED, 1, _(" Could not stat %s: ERR=%s\n"), ff_pkt->fname, be.bstrerror());
147 Jmsg(jcr, M_SKIPPED, 1, _(" Unchanged file skipped: %s\n"), ff_pkt->fname);
150 Jmsg(jcr, M_SKIPPED, 1, _(" Archive file skipped: %s\n"), ff_pkt->fname);
153 Jmsg(jcr, M_SKIPPED, 1, _(" Recursion turned off. Directory skipped: %s\n"), ff_pkt->fname);
154 ff_pkt->type = FT_DIREND; /* directory entry was backed up */
157 Jmsg(jcr, M_SKIPPED, 1, _(" File system change prohibited. Directory skipped: %s\n"), ff_pkt->fname);
159 case FT_PLUGIN_CONFIG:
160 case FT_RESTORE_FIRST:
161 return 1; /* silently skip */
164 be.set_errno(ff_pkt->ff_errno);
165 Jmsg(jcr, M_NOTSAVED, 1, _(" Could not open directory %s: ERR=%s\n"), ff_pkt->fname, be.bstrerror());
170 Jmsg(jcr, M_NOTSAVED, 0, _(" Unknown file type %d: %s\n"), ff_pkt->type, ff_pkt->fname);
175 /* Encode attributes and possibly extend them */
176 encode_stat(attribs, &ff_pkt->statp, sizeof(ff_pkt->statp), ff_pkt->LinkFI, 0);
177 encode_attribsEx(jcr, attribsEx, ff_pkt);
180 jcr->JobFiles++; /* increment number of files sent */
181 pm_strcpy(jcr->last_fname, ff_pkt->fname);
185 * Send file attributes to Director
189 * Filename (full path)
191 * Link name (if type==FT_LNK)
192 * For a directory, link is the same as fname, but with trailing
193 * slash. For a linked file, link is the link.
195 /* Send file attributes to Director (note different format than for Storage) */
196 Dmsg2(400, "send ATTR inx=%d fname=%s\n", jcr->JobFiles, ff_pkt->fname);
197 if (ff_pkt->type == FT_LNK || ff_pkt->type == FT_LNKSAVED) {
198 stat = dir->fsend("%d %d %s %s%c%s%c%s%c", jcr->JobFiles,
199 STREAM_UNIX_ATTRIBUTES, ff_pkt->VerifyOpts, ff_pkt->fname,
200 0, attribs, 0, ff_pkt->link, 0);
201 } else if (ff_pkt->type == FT_DIREND || ff_pkt->type == FT_REPARSE ||
202 ff_pkt->type == FT_JUNCTION) {
203 /* Here link is the canonical filename (i.e. with trailing slash) */
204 stat = dir->fsend("%d %d %s %s%c%s%c%c", jcr->JobFiles,
205 STREAM_UNIX_ATTRIBUTES, ff_pkt->VerifyOpts, ff_pkt->link,
208 stat = dir->fsend("%d %d %s %s%c%s%c%c", jcr->JobFiles,
209 STREAM_UNIX_ATTRIBUTES, ff_pkt->VerifyOpts, ff_pkt->fname,
212 Dmsg2(20, "bfiled>bdird: attribs len=%d: msg=%s\n", dir->msglen, dir->msg);
214 Jmsg(jcr, M_FATAL, 0, _("Network error in send to Director: ERR=%s\n"), bnet_strerror(dir));
219 * The remainder of the function is all about getting the checksum.
220 * First we initialise, then we read files, other streams and Finder Info.
222 if (ff_pkt->type != FT_LNKSAVED && (S_ISREG(ff_pkt->statp.st_mode) &&
223 ff_pkt->flags & (FO_MD5|FO_SHA1|FO_SHA256|FO_SHA512))) {
225 * Create our digest context. If this fails, the digest will be set to NULL
228 if (ff_pkt->flags & FO_MD5) {
229 digest = crypto_digest_new(jcr, CRYPTO_DIGEST_MD5);
230 digest_stream = STREAM_MD5_DIGEST;
232 } else if (ff_pkt->flags & FO_SHA1) {
233 digest = crypto_digest_new(jcr, CRYPTO_DIGEST_SHA1);
234 digest_stream = STREAM_SHA1_DIGEST;
236 } else if (ff_pkt->flags & FO_SHA256) {
237 digest = crypto_digest_new(jcr, CRYPTO_DIGEST_SHA256);
238 digest_stream = STREAM_SHA256_DIGEST;
240 } else if (ff_pkt->flags & FO_SHA512) {
241 digest = crypto_digest_new(jcr, CRYPTO_DIGEST_SHA512);
242 digest_stream = STREAM_SHA512_DIGEST;
245 /* Did digest initialization fail? */
246 if (digest_stream != STREAM_NONE && digest == NULL) {
247 Jmsg(jcr, M_WARNING, 0, _("%s digest initialization failed\n"),
248 stream_to_ascii(digest_stream));
251 /* compute MD5 or SHA1 hash */
253 char md[CRYPTO_DIGEST_MAX_SIZE];
258 if (digest_file(jcr, ff_pkt, digest) != 0) {
263 if (crypto_digest_finalize(digest, (uint8_t *)md, &size)) {
265 const char *digest_name;
267 digest_buf = (char *)malloc(BASE64_SIZE(size));
268 digest_name = crypto_digest_name(digest);
270 bin_to_base64(digest_buf, BASE64_SIZE(size), md, size, true);
271 Dmsg3(400, "send inx=%d %s=%s\n", jcr->JobFiles, digest_name, digest_buf);
272 dir->fsend("%d %d %s *%s-%d*", jcr->JobFiles, digest_stream, digest_buf,
273 digest_name, jcr->JobFiles);
274 Dmsg3(20, "bfiled>bdird: %s len=%d: msg=%s\n", digest_name,
275 dir->msglen, dir->msg);
284 crypto_digest_free(digest);
290 * Compute message digest for the file specified by ff_pkt.
291 * In case of errors we need the job control record and file name.
293 int digest_file(JCR *jcr, FF_PKT *ff_pkt, DIGEST *digest)
297 Dmsg0(50, "=== digest_file\n");
300 if (ff_pkt->statp.st_size > 0 ||
301 ff_pkt->type == FT_RAW ||
302 ff_pkt->type == FT_FIFO) {
303 int noatime = ff_pkt->flags & FO_NOATIME ? O_NOATIME : 0;
304 if ((bopen(&bfd, ff_pkt->fname, O_RDONLY | O_BINARY | noatime, 0)) < 0) {
305 ff_pkt->ff_errno = errno;
307 be.set_errno(bfd.berrno);
308 Dmsg2(100, "Cannot open %s: ERR=%s\n", ff_pkt->fname, be.bstrerror());
309 Jmsg(jcr, M_ERROR, 1, _(" Cannot open %s: ERR=%s.\n"),
310 ff_pkt->fname, be.bstrerror());
313 read_digest(&bfd, digest, jcr);
317 if (have_darwin_os) {
318 /* Open resource fork if necessary */
319 if (ff_pkt->flags & FO_HFSPLUS && ff_pkt->hfsinfo.rsrclength > 0) {
320 if (bopen_rsrc(&bfd, ff_pkt->fname, O_RDONLY | O_BINARY, 0) < 0) {
321 ff_pkt->ff_errno = errno;
323 Jmsg(jcr, M_ERROR, -1, _(" Cannot open resource fork for %s: ERR=%s.\n"),
324 ff_pkt->fname, be.bstrerror());
325 if (is_bopen(&ff_pkt->bfd)) {
326 bclose(&ff_pkt->bfd);
330 read_digest(&bfd, digest, jcr);
334 if (digest && ff_pkt->flags & FO_HFSPLUS) {
335 crypto_digest_update(digest, (uint8_t *)ff_pkt->hfsinfo.fndrinfo, 32);
342 * Read message digest of bfd, updating digest
343 * In case of errors we need the job control record and file name.
345 static int read_digest(BFILE *bfd, DIGEST *digest, JCR *jcr)
347 char buf[DEFAULT_NETWORK_BUFFER_SIZE];
349 int64_t bufsiz = (int64_t)sizeof(buf);
350 FF_PKT *ff_pkt = (FF_PKT *)jcr->ff;
351 uint64_t fileAddr = 0; /* file address */
354 Dmsg0(50, "=== read_digest\n");
355 while ((n=bread(bfd, buf, bufsiz)) > 0) {
356 /* Check for sparse blocks */
357 if (ff_pkt->flags & FO_SPARSE) {
358 bool allZeros = false;
360 fileAddr+n < (uint64_t)ff_pkt->statp.st_size) ||
361 ((ff_pkt->type == FT_RAW || ff_pkt->type == FT_FIFO) &&
362 (uint64_t)ff_pkt->statp.st_size == 0)) {
363 allZeros = is_buf_zero(buf, bufsiz);
365 fileAddr += n; /* update file address */
366 /* Skip any block of all zeros */
368 continue; /* skip block of zeros */
372 crypto_digest_update(digest, (uint8_t *)buf, n);
374 /* Can be used by BaseJobs or with accurate, update only for Verify
377 if (jcr->getJobType() == JT_VERIFY) {
384 be.set_errno(bfd->berrno);
385 Dmsg2(100, "Error reading file %s: ERR=%s\n", jcr->last_fname, be.bstrerror());
386 Jmsg(jcr, M_ERROR, 1, _("Error reading file %s: ERR=%s\n"),
387 jcr->last_fname, be.bstrerror());