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 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_RESTORE_FIRST:
160 return 1; /* silently skip */
163 be.set_errno(ff_pkt->ff_errno);
164 Jmsg(jcr, M_NOTSAVED, 1, _(" Could not open directory %s: ERR=%s\n"), ff_pkt->fname, be.bstrerror());
169 Jmsg(jcr, M_NOTSAVED, 0, _(" Unknown file type %d: %s\n"), ff_pkt->type, ff_pkt->fname);
174 /* Encode attributes and possibly extend them */
175 encode_stat(attribs, &ff_pkt->statp, ff_pkt->LinkFI, 0);
176 encode_attribsEx(jcr, attribsEx, ff_pkt);
179 jcr->JobFiles++; /* increment number of files sent */
180 pm_strcpy(jcr->last_fname, ff_pkt->fname);
184 * Send file attributes to Director
188 * Filename (full path)
190 * Link name (if type==FT_LNK)
191 * For a directory, link is the same as fname, but with trailing
192 * slash. For a linked file, link is the link.
194 /* Send file attributes to Director (note different format than for Storage) */
195 Dmsg2(400, "send ATTR inx=%d fname=%s\n", jcr->JobFiles, ff_pkt->fname);
196 if (ff_pkt->type == FT_LNK || ff_pkt->type == FT_LNKSAVED) {
197 stat = dir->fsend("%d %d %s %s%c%s%c%s%c", jcr->JobFiles,
198 STREAM_UNIX_ATTRIBUTES, ff_pkt->VerifyOpts, ff_pkt->fname,
199 0, attribs, 0, ff_pkt->link, 0);
200 } else if (ff_pkt->type == FT_DIREND || ff_pkt->type == FT_REPARSE ||
201 ff_pkt->type == FT_JUNCTION) {
202 /* Here link is the canonical filename (i.e. with trailing slash) */
203 stat = dir->fsend("%d %d %s %s%c%s%c%c", jcr->JobFiles,
204 STREAM_UNIX_ATTRIBUTES, ff_pkt->VerifyOpts, ff_pkt->link,
207 stat = dir->fsend("%d %d %s %s%c%s%c%c", jcr->JobFiles,
208 STREAM_UNIX_ATTRIBUTES, ff_pkt->VerifyOpts, ff_pkt->fname,
211 Dmsg2(20, "bfiled>bdird: attribs len=%d: msg=%s\n", dir->msglen, dir->msg);
213 Jmsg(jcr, M_FATAL, 0, _("Network error in send to Director: ERR=%s\n"), bnet_strerror(dir));
218 * The remainder of the function is all about getting the checksum.
219 * First we initialise, then we read files, other streams and Finder Info.
221 if (ff_pkt->type != FT_LNKSAVED && (S_ISREG(ff_pkt->statp.st_mode) &&
222 ff_pkt->flags & (FO_MD5|FO_SHA1|FO_SHA256|FO_SHA512))) {
224 * Create our digest context. If this fails, the digest will be set to NULL
227 if (ff_pkt->flags & FO_MD5) {
228 digest = crypto_digest_new(jcr, CRYPTO_DIGEST_MD5);
229 digest_stream = STREAM_MD5_DIGEST;
231 } else if (ff_pkt->flags & FO_SHA1) {
232 digest = crypto_digest_new(jcr, CRYPTO_DIGEST_SHA1);
233 digest_stream = STREAM_SHA1_DIGEST;
235 } else if (ff_pkt->flags & FO_SHA256) {
236 digest = crypto_digest_new(jcr, CRYPTO_DIGEST_SHA256);
237 digest_stream = STREAM_SHA256_DIGEST;
239 } else if (ff_pkt->flags & FO_SHA512) {
240 digest = crypto_digest_new(jcr, CRYPTO_DIGEST_SHA512);
241 digest_stream = STREAM_SHA512_DIGEST;
244 /* Did digest initialization fail? */
245 if (digest_stream != STREAM_NONE && digest == NULL) {
246 Jmsg(jcr, M_WARNING, 0, _("%s digest initialization failed\n"),
247 stream_to_ascii(digest_stream));
250 /* compute MD5 or SHA1 hash */
252 char md[CRYPTO_DIGEST_MAX_SIZE];
257 if (digest_file(jcr, ff_pkt, digest) != 0) {
262 if (crypto_digest_finalize(digest, (uint8_t *)md, &size)) {
264 const char *digest_name;
266 digest_buf = (char *)malloc(BASE64_SIZE(size));
267 digest_name = crypto_digest_name(digest);
269 bin_to_base64(digest_buf, BASE64_SIZE(size), md, size, true);
270 Dmsg3(400, "send inx=%d %s=%s\n", jcr->JobFiles, digest_name, digest_buf);
271 dir->fsend("%d %d %s *%s-%d*", jcr->JobFiles, digest_stream, digest_buf,
272 digest_name, jcr->JobFiles);
273 Dmsg3(20, "bfiled>bdird: %s len=%d: msg=%s\n", digest_name,
274 dir->msglen, dir->msg);
283 crypto_digest_free(digest);
289 * Compute message digest for the file specified by ff_pkt.
290 * In case of errors we need the job control record and file name.
292 int digest_file(JCR *jcr, FF_PKT *ff_pkt, DIGEST *digest)
296 Dmsg0(50, "=== digest_file\n");
299 if (ff_pkt->statp.st_size > 0 ||
300 ff_pkt->type == FT_RAW ||
301 ff_pkt->type == FT_FIFO) {
302 int noatime = ff_pkt->flags & FO_NOATIME ? O_NOATIME : 0;
303 if ((bopen(&bfd, ff_pkt->fname, O_RDONLY | O_BINARY | noatime, 0)) < 0) {
304 ff_pkt->ff_errno = errno;
306 be.set_errno(bfd.berrno);
307 Dmsg2(100, "Cannot open %s: ERR=%s\n", ff_pkt->fname, be.bstrerror());
308 Jmsg(jcr, M_ERROR, 1, _(" Cannot open %s: ERR=%s.\n"),
309 ff_pkt->fname, be.bstrerror());
312 read_digest(&bfd, digest, jcr);
316 if (have_darwin_os) {
317 /* Open resource fork if necessary */
318 if (ff_pkt->flags & FO_HFSPLUS && ff_pkt->hfsinfo.rsrclength > 0) {
319 if (bopen_rsrc(&bfd, ff_pkt->fname, O_RDONLY | O_BINARY, 0) < 0) {
320 ff_pkt->ff_errno = errno;
322 Jmsg(jcr, M_ERROR, -1, _(" Cannot open resource fork for %s: ERR=%s.\n"),
323 ff_pkt->fname, be.bstrerror());
324 if (is_bopen(&ff_pkt->bfd)) {
325 bclose(&ff_pkt->bfd);
329 read_digest(&bfd, digest, jcr);
333 if (digest && ff_pkt->flags & FO_HFSPLUS) {
334 crypto_digest_update(digest, (uint8_t *)ff_pkt->hfsinfo.fndrinfo, 32);
341 * Read message digest of bfd, updating digest
342 * In case of errors we need the job control record and file name.
344 static int read_digest(BFILE *bfd, DIGEST *digest, JCR *jcr)
346 char buf[DEFAULT_NETWORK_BUFFER_SIZE];
348 int64_t bufsiz = (int64_t)sizeof(buf);
349 FF_PKT *ff_pkt = (FF_PKT *)jcr->ff;
350 uint64_t fileAddr = 0; /* file address */
353 Dmsg0(50, "=== read_digest\n");
354 while ((n=bread(bfd, buf, bufsiz)) > 0) {
355 /* Check for sparse blocks */
356 if (ff_pkt->flags & FO_SPARSE) {
357 bool allZeros = false;
359 fileAddr+n < (uint64_t)ff_pkt->statp.st_size) ||
360 ((ff_pkt->type == FT_RAW || ff_pkt->type == FT_FIFO) &&
361 (uint64_t)ff_pkt->statp.st_size == 0)) {
362 allZeros = is_buf_zero(buf, bufsiz);
364 fileAddr += n; /* update file address */
365 /* Skip any block of all zeros */
367 continue; /* skip block of zeros */
371 crypto_digest_update(digest, (uint8_t *)buf, n);
373 /* Can be used by BaseJobs or with accurate, update only for Verify
376 if (jcr->getJobType() == JT_VERIFY) {
383 be.set_errno(bfd->berrno);
384 Dmsg2(100, "Error reading file %s: ERR=%s\n", jcr->last_fname, be.bstrerror());
385 Jmsg(jcr, M_ERROR, 1, _("Error reading file %s: ERR=%s\n"),
386 jcr->last_fname, be.bstrerror());