2 Bacula® - The Network Backup Solution
4 Copyright (C) 2000-2010 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 two of the GNU 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 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 set_jcr_job_status(jcr, 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 set_jcr_job_status(jcr, 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 */
112 Dmsg1(30, "FT_DIR saving: %s\n", ff_pkt->fname);
115 Dmsg1(30, "FT_SPEC saving: %s\n", ff_pkt->fname);
118 Dmsg1(30, "FT_RAW saving: %s\n", ff_pkt->fname);
121 Dmsg1(30, "FT_FIFO saving: %s\n", ff_pkt->fname);
125 be.set_errno(ff_pkt->ff_errno);
126 Jmsg(jcr, M_NOTSAVED, 1, _(" Could not access %s: ERR=%s\n"), ff_pkt->fname, be.bstrerror());
132 be.set_errno(ff_pkt->ff_errno);
133 Jmsg(jcr, M_NOTSAVED, 1, _(" Could not follow link %s: ERR=%s\n"), ff_pkt->fname, be.bstrerror());
139 be.set_errno(ff_pkt->ff_errno);
140 Jmsg(jcr, M_NOTSAVED, 1, _(" Could not stat %s: ERR=%s\n"), ff_pkt->fname, be.bstrerror());
146 Jmsg(jcr, M_SKIPPED, 1, _(" Unchanged file skipped: %s\n"), ff_pkt->fname);
149 Jmsg(jcr, M_SKIPPED, 1, _(" Archive file skipped: %s\n"), ff_pkt->fname);
152 Jmsg(jcr, M_SKIPPED, 1, _(" Recursion turned off. Directory skipped: %s\n"), ff_pkt->fname);
153 ff_pkt->type = FT_DIREND; /* directory entry was backed up */
156 Jmsg(jcr, M_SKIPPED, 1, _(" File system change prohibited. Directory skipped: %s\n"), ff_pkt->fname);
160 be.set_errno(ff_pkt->ff_errno);
161 Jmsg(jcr, M_NOTSAVED, 1, _(" Could not open directory %s: ERR=%s\n"), ff_pkt->fname, be.bstrerror());
166 Jmsg(jcr, M_NOTSAVED, 0, _(" Unknown file type %d: %s\n"), ff_pkt->type, ff_pkt->fname);
171 /* Encode attributes and possibly extend them */
172 encode_stat(attribs, &ff_pkt->statp, ff_pkt->LinkFI, 0);
173 encode_attribsEx(jcr, attribsEx, ff_pkt);
176 jcr->JobFiles++; /* increment number of files sent */
177 pm_strcpy(jcr->last_fname, ff_pkt->fname);
181 * Send file attributes to Director
185 * Filename (full path)
187 * Link name (if type==FT_LNK)
188 * For a directory, link is the same as fname, but with trailing
189 * slash. For a linked file, link is the link.
191 /* Send file attributes to Director (note different format than for Storage) */
192 Dmsg2(400, "send ATTR inx=%d fname=%s\n", jcr->JobFiles, ff_pkt->fname);
193 if (ff_pkt->type == FT_LNK || ff_pkt->type == FT_LNKSAVED) {
194 stat = dir->fsend("%d %d %s %s%c%s%c%s%c", jcr->JobFiles,
195 STREAM_UNIX_ATTRIBUTES, ff_pkt->VerifyOpts, ff_pkt->fname,
196 0, attribs, 0, ff_pkt->link, 0);
197 } else if (ff_pkt->type == FT_DIREND || ff_pkt->type == FT_REPARSE) {
198 /* Here link is the canonical filename (i.e. with trailing slash) */
199 stat = dir->fsend("%d %d %s %s%c%s%c%c", jcr->JobFiles,
200 STREAM_UNIX_ATTRIBUTES, ff_pkt->VerifyOpts, ff_pkt->link,
203 stat = dir->fsend("%d %d %s %s%c%s%c%c", jcr->JobFiles,
204 STREAM_UNIX_ATTRIBUTES, ff_pkt->VerifyOpts, ff_pkt->fname,
207 Dmsg2(20, "bfiled>bdird: attribs len=%d: msg=%s\n", dir->msglen, dir->msg);
209 Jmsg(jcr, M_FATAL, 0, _("Network error in send to Director: ERR=%s\n"), bnet_strerror(dir));
214 * The remainder of the function is all about getting the checksum.
215 * First we initialise, then we read files, other streams and Finder Info.
217 if (ff_pkt->type != FT_LNKSAVED && (S_ISREG(ff_pkt->statp.st_mode) &&
218 ff_pkt->flags & (FO_MD5|FO_SHA1|FO_SHA256|FO_SHA512))) {
220 * Create our digest context. If this fails, the digest will be set to NULL
223 if (ff_pkt->flags & FO_MD5) {
224 digest = crypto_digest_new(jcr, CRYPTO_DIGEST_MD5);
225 digest_stream = STREAM_MD5_DIGEST;
227 } else if (ff_pkt->flags & FO_SHA1) {
228 digest = crypto_digest_new(jcr, CRYPTO_DIGEST_SHA1);
229 digest_stream = STREAM_SHA1_DIGEST;
231 } else if (ff_pkt->flags & FO_SHA256) {
232 digest = crypto_digest_new(jcr, CRYPTO_DIGEST_SHA256);
233 digest_stream = STREAM_SHA256_DIGEST;
235 } else if (ff_pkt->flags & FO_SHA512) {
236 digest = crypto_digest_new(jcr, CRYPTO_DIGEST_SHA512);
237 digest_stream = STREAM_SHA512_DIGEST;
240 /* Did digest initialization fail? */
241 if (digest_stream != STREAM_NONE && digest == NULL) {
242 Jmsg(jcr, M_WARNING, 0, _("%s digest initialization failed\n"),
243 stream_to_ascii(digest_stream));
246 /* compute MD5 or SHA1 hash */
248 char md[CRYPTO_DIGEST_MAX_SIZE];
253 if (digest_file(jcr, ff_pkt, digest) != 0) {
258 if (crypto_digest_finalize(digest, (uint8_t *)md, &size)) {
260 const char *digest_name;
262 digest_buf = (char *)malloc(BASE64_SIZE(size));
263 digest_name = crypto_digest_name(digest);
265 bin_to_base64(digest_buf, BASE64_SIZE(size), md, size, true);
266 Dmsg3(400, "send inx=%d %s=%s\n", jcr->JobFiles, digest_name, digest_buf);
267 dir->fsend("%d %d %s *%s-%d*", jcr->JobFiles, digest_stream, digest_buf,
268 digest_name, jcr->JobFiles);
269 Dmsg3(20, "bfiled>bdird: %s len=%d: msg=%s\n", digest_name,
270 dir->msglen, dir->msg);
279 crypto_digest_free(digest);
285 * Compute message digest for the file specified by ff_pkt.
286 * In case of errors we need the job control record and file name.
288 int digest_file(JCR *jcr, FF_PKT *ff_pkt, DIGEST *digest)
292 Dmsg0(50, "=== digest_file\n");
295 if (ff_pkt->statp.st_size > 0 ||
296 ff_pkt->type == FT_RAW ||
297 ff_pkt->type == FT_FIFO) {
298 int noatime = ff_pkt->flags & FO_NOATIME ? O_NOATIME : 0;
299 if ((bopen(&bfd, ff_pkt->fname, O_RDONLY | O_BINARY | noatime, 0)) < 0) {
300 ff_pkt->ff_errno = errno;
302 be.set_errno(bfd.berrno);
303 Dmsg2(100, "Cannot open %s: ERR=%s\n", ff_pkt->fname, be.bstrerror());
304 Jmsg(jcr, M_ERROR, 1, _(" Cannot open %s: ERR=%s.\n"),
305 ff_pkt->fname, be.bstrerror());
308 read_digest(&bfd, digest, jcr);
312 if (have_darwin_os) {
313 /* Open resource fork if necessary */
314 if (ff_pkt->flags & FO_HFSPLUS && ff_pkt->hfsinfo.rsrclength > 0) {
315 if (bopen_rsrc(&bfd, ff_pkt->fname, O_RDONLY | O_BINARY, 0) < 0) {
316 ff_pkt->ff_errno = errno;
318 Jmsg(jcr, M_ERROR, -1, _(" Cannot open resource fork for %s: ERR=%s.\n"),
319 ff_pkt->fname, be.bstrerror());
320 if (is_bopen(&ff_pkt->bfd)) {
321 bclose(&ff_pkt->bfd);
325 read_digest(&bfd, digest, jcr);
329 if (digest && ff_pkt->flags & FO_HFSPLUS) {
330 crypto_digest_update(digest, (uint8_t *)ff_pkt->hfsinfo.fndrinfo, 32);
337 * Read message digest of bfd, updating digest
338 * In case of errors we need the job control record and file name.
340 static int read_digest(BFILE *bfd, DIGEST *digest, JCR *jcr)
342 char buf[DEFAULT_NETWORK_BUFFER_SIZE];
344 int64_t bufsiz = (int64_t)sizeof(buf);
345 FF_PKT *ff_pkt = (FF_PKT *)jcr->ff;
346 uint64_t fileAddr = 0; /* file address */
349 Dmsg0(50, "=== read_digest\n");
350 while ((n=bread(bfd, buf, bufsiz)) > 0) {
351 /* Check for sparse blocks */
352 if (ff_pkt->flags & FO_SPARSE) {
353 bool allZeros = false;
355 fileAddr+n < (uint64_t)ff_pkt->statp.st_size) ||
356 ((ff_pkt->type == FT_RAW || ff_pkt->type == FT_FIFO) &&
357 (uint64_t)ff_pkt->statp.st_size == 0)) {
358 allZeros = is_buf_zero(buf, bufsiz);
360 fileAddr += n; /* update file address */
361 /* Skip any block of all zeros */
363 continue; /* skip block of zeros */
367 crypto_digest_update(digest, (uint8_t *)buf, n);
369 /* Can be used by BaseJobs, update only for Verify jobs */
370 if (jcr->getJobLevel() != L_FULL) {
377 be.set_errno(bfd->berrno);
378 Dmsg2(100, "Error reading file %s: ERR=%s\n", jcr->last_fname, be.bstrerror());
379 Jmsg(jcr, M_ERROR, 1, _("Error reading file %s: ERR=%s\n"),
380 jcr->last_fname, be.bstrerror());