2 Bacula® - The Network Backup Solution
4 Copyright (C) 2000-2009 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
41 const bool have_darwin_os = true;
43 const bool have_darwin_os = false;
46 static int verify_file(JCR *jcr, FF_PKT *ff_pkt, bool);
47 static int read_digest(BFILE *bfd, DIGEST *digest, JCR *jcr);
50 * Find all the requested files and send attributes
54 void do_verify(JCR *jcr)
56 set_jcr_job_status(jcr, JS_Running);
57 jcr->buf_size = DEFAULT_NETWORK_BUFFER_SIZE;
58 if ((jcr->big_buf = (char *) malloc(jcr->buf_size)) == NULL) {
59 Jmsg1(jcr, M_ABORT, 0, _("Cannot malloc %d network read buffer\n"),
60 DEFAULT_NETWORK_BUFFER_SIZE);
62 set_find_options((FF_PKT *)jcr->ff, jcr->incremental, jcr->mtime);
63 Dmsg0(10, "Start find files\n");
64 /* Subroutine verify_file() is called for each file */
65 find_files(jcr, (FF_PKT *)jcr->ff, verify_file, NULL);
66 Dmsg0(10, "End find files\n");
72 set_jcr_job_status(jcr, JS_Terminated);
76 * Called here by find() for each file.
78 * Find the file, compute the MD5 or SHA1 and send it back to the Director
80 static int verify_file(JCR *jcr, FF_PKT *ff_pkt, bool top_level)
82 char attribs[MAXSTRING];
83 char attribsEx[MAXSTRING];
84 int digest_stream = STREAM_NONE;
86 DIGEST *digest = NULL;
89 if (job_canceled(jcr)) {
94 jcr->num_files_examined++; /* bump total file count */
96 switch (ff_pkt->type) {
97 case FT_LNKSAVED: /* Hard linked, file already saved */
98 Dmsg2(30, "FT_LNKSAVED saving: %s => %s\n", ff_pkt->fname, ff_pkt->link);
101 Dmsg1(30, "FT_REGE saving: %s\n", ff_pkt->fname);
104 Dmsg1(30, "FT_REG saving: %s\n", ff_pkt->fname);
107 Dmsg2(30, "FT_LNK saving: %s -> %s\n", ff_pkt->fname, ff_pkt->link);
110 jcr->num_files_examined--; /* correct file count */
111 return 1; /* ignored */
114 Dmsg1(30, "FT_DIR saving: %s\n", ff_pkt->fname);
117 Dmsg1(30, "FT_SPEC saving: %s\n", ff_pkt->fname);
120 Dmsg1(30, "FT_RAW saving: %s\n", ff_pkt->fname);
123 Dmsg1(30, "FT_FIFO saving: %s\n", ff_pkt->fname);
127 be.set_errno(ff_pkt->ff_errno);
128 Jmsg(jcr, M_NOTSAVED, 1, _(" Could not access %s: ERR=%s\n"), ff_pkt->fname, be.bstrerror());
134 be.set_errno(ff_pkt->ff_errno);
135 Jmsg(jcr, M_NOTSAVED, 1, _(" Could not follow link %s: ERR=%s\n"), ff_pkt->fname, be.bstrerror());
141 be.set_errno(ff_pkt->ff_errno);
142 Jmsg(jcr, M_NOTSAVED, 1, _(" Could not stat %s: ERR=%s\n"), ff_pkt->fname, be.bstrerror());
148 Jmsg(jcr, M_SKIPPED, 1, _(" Unchanged file skipped: %s\n"), ff_pkt->fname);
151 Jmsg(jcr, M_SKIPPED, 1, _(" Archive file skipped: %s\n"), ff_pkt->fname);
154 Jmsg(jcr, M_SKIPPED, 1, _(" Recursion turned off. Directory skipped: %s\n"), ff_pkt->fname);
155 ff_pkt->type = FT_DIREND; /* directory entry was backed up */
158 Jmsg(jcr, M_SKIPPED, 1, _(" File system change prohibited. Directory skipped: %s\n"), ff_pkt->fname);
162 be.set_errno(ff_pkt->ff_errno);
163 Jmsg(jcr, M_NOTSAVED, 1, _(" Could not open directory %s: ERR=%s\n"), ff_pkt->fname, be.bstrerror());
168 Jmsg(jcr, M_NOTSAVED, 0, _(" Unknown file type %d: %s\n"), ff_pkt->type, ff_pkt->fname);
173 /* Encode attributes and possibly extend them */
174 encode_stat(attribs, &ff_pkt->statp, ff_pkt->LinkFI, 0);
175 encode_attribsEx(jcr, attribsEx, ff_pkt);
178 jcr->JobFiles++; /* increment number of files sent */
179 pm_strcpy(jcr->last_fname, ff_pkt->fname);
183 * Send file attributes to Director
187 * Filename (full path)
189 * Link name (if type==FT_LNK)
190 * For a directory, link is the same as fname, but with trailing
191 * slash. For a linked file, link is the link.
193 /* Send file attributes to Director (note different format than for Storage) */
194 Dmsg2(400, "send ATTR inx=%d fname=%s\n", jcr->JobFiles, ff_pkt->fname);
195 if (ff_pkt->type == FT_LNK || ff_pkt->type == FT_LNKSAVED) {
196 stat = dir->fsend("%d %d %s %s%c%s%c%s%c", jcr->JobFiles,
197 STREAM_UNIX_ATTRIBUTES, ff_pkt->VerifyOpts, ff_pkt->fname,
198 0, attribs, 0, ff_pkt->link, 0);
199 } else if (ff_pkt->type == FT_DIREND || ff_pkt->type == FT_REPARSE) {
200 /* Here link is the canonical filename (i.e. with trailing slash) */
201 stat = dir->fsend("%d %d %s %s%c%s%c%c", jcr->JobFiles,
202 STREAM_UNIX_ATTRIBUTES, ff_pkt->VerifyOpts, ff_pkt->link,
205 stat = dir->fsend("%d %d %s %s%c%s%c%c", jcr->JobFiles,
206 STREAM_UNIX_ATTRIBUTES, ff_pkt->VerifyOpts, ff_pkt->fname,
209 Dmsg2(20, "bfiled>bdird: attribs len=%d: msg=%s\n", dir->msglen, dir->msg);
211 Jmsg(jcr, M_FATAL, 0, _("Network error in send to Director: ERR=%s\n"), bnet_strerror(dir));
216 * The remainder of the function is all about getting the checksum.
217 * First we initialise, then we read files, other streams and Finder Info.
219 if (ff_pkt->type != FT_LNKSAVED && (S_ISREG(ff_pkt->statp.st_mode) &&
220 ff_pkt->flags & (FO_MD5|FO_SHA1|FO_SHA256|FO_SHA512))) {
222 * Create our digest context. If this fails, the digest will be set to NULL
225 if (ff_pkt->flags & FO_MD5) {
226 digest = crypto_digest_new(jcr, CRYPTO_DIGEST_MD5);
227 digest_stream = STREAM_MD5_DIGEST;
229 } else if (ff_pkt->flags & FO_SHA1) {
230 digest = crypto_digest_new(jcr, CRYPTO_DIGEST_SHA1);
231 digest_stream = STREAM_SHA1_DIGEST;
233 } else if (ff_pkt->flags & FO_SHA256) {
234 digest = crypto_digest_new(jcr, CRYPTO_DIGEST_SHA256);
235 digest_stream = STREAM_SHA256_DIGEST;
237 } else if (ff_pkt->flags & FO_SHA512) {
238 digest = crypto_digest_new(jcr, CRYPTO_DIGEST_SHA512);
239 digest_stream = STREAM_SHA512_DIGEST;
242 /* Did digest initialization fail? */
243 if (digest_stream != STREAM_NONE && digest == NULL) {
244 Jmsg(jcr, M_WARNING, 0, _("%s digest initialization failed\n"),
245 stream_to_ascii(digest_stream));
248 /* compute MD5 or SHA1 hash */
250 char md[CRYPTO_DIGEST_MAX_SIZE];
255 if (digest_file(jcr, ff_pkt, digest) != 0) {
260 if (crypto_digest_finalize(digest, (uint8_t *)md, &size)) {
262 const char *digest_name;
264 digest_buf = (char *)malloc(BASE64_SIZE(size));
265 digest_name = crypto_digest_name(digest);
267 bin_to_base64(digest_buf, BASE64_SIZE(size), md, size, true);
268 Dmsg3(400, "send inx=%d %s=%s\n", jcr->JobFiles, digest_name, digest_buf);
269 dir->fsend("%d %d %s *%s-%d*", jcr->JobFiles, digest_stream, digest_buf,
270 digest_name, jcr->JobFiles);
271 Dmsg3(20, "bfiled>bdird: %s len=%d: msg=%s\n", digest_name,
272 dir->msglen, dir->msg);
281 crypto_digest_free(digest);
287 * Compute message digest for the file specified by ff_pkt.
288 * In case of errors we need the job control record and file name.
290 int digest_file(JCR *jcr, FF_PKT *ff_pkt, DIGEST *digest)
294 Dmsg0(50, "=== digest_file\n");
297 if (ff_pkt->statp.st_size > 0 ||
298 ff_pkt->type == FT_RAW ||
299 ff_pkt->type == FT_FIFO) {
300 int noatime = ff_pkt->flags & FO_NOATIME ? O_NOATIME : 0;
301 if ((bopen(&bfd, ff_pkt->fname, O_RDONLY | O_BINARY | noatime, 0)) < 0) {
302 ff_pkt->ff_errno = errno;
304 be.set_errno(bfd.berrno);
305 Dmsg2(100, "Cannot open %s: ERR=%s\n", ff_pkt->fname, be.bstrerror());
306 Jmsg(jcr, M_ERROR, 1, _(" Cannot open %s: ERR=%s.\n"),
307 ff_pkt->fname, be.bstrerror());
310 read_digest(&bfd, digest, jcr);
314 if (have_darwin_os) {
315 /* Open resource fork if necessary */
316 if (ff_pkt->flags & FO_HFSPLUS && ff_pkt->hfsinfo.rsrclength > 0) {
317 if (bopen_rsrc(&bfd, ff_pkt->fname, O_RDONLY | O_BINARY, 0) < 0) {
318 ff_pkt->ff_errno = errno;
320 Jmsg(jcr, M_ERROR, -1, _(" Cannot open resource fork for %s: ERR=%s.\n"),
321 ff_pkt->fname, be.bstrerror());
322 if (is_bopen(&ff_pkt->bfd)) {
323 bclose(&ff_pkt->bfd);
327 read_digest(&bfd, digest, jcr);
331 if (digest && ff_pkt->flags & FO_HFSPLUS) {
332 crypto_digest_update(digest, (uint8_t *)ff_pkt->hfsinfo.fndrinfo, 32);
339 * Read message digest of bfd, updating digest
340 * In case of errors we need the job control record and file name.
342 static int read_digest(BFILE *bfd, DIGEST *digest, JCR *jcr)
344 char buf[DEFAULT_NETWORK_BUFFER_SIZE];
346 int64_t bufsiz = (int64_t)sizeof(buf);
347 FF_PKT *ff_pkt = (FF_PKT *)jcr->ff;
348 uint64_t fileAddr = 0; /* file address */
351 Dmsg0(50, "=== read_digest\n");
352 while ((n=bread(bfd, buf, bufsiz)) > 0) {
353 /* Check for sparse blocks */
354 if (ff_pkt->flags & FO_SPARSE) {
355 bool allZeros = false;
357 fileAddr+n < (uint64_t)ff_pkt->statp.st_size) ||
358 ((ff_pkt->type == FT_RAW || ff_pkt->type == FT_FIFO) &&
359 (uint64_t)ff_pkt->statp.st_size == 0)) {
360 allZeros = is_buf_zero(buf, bufsiz);
362 fileAddr += n; /* update file address */
363 /* Skip any block of all zeros */
365 continue; /* skip block of zeros */
369 crypto_digest_update(digest, (uint8_t *)buf, n);
371 /* Can be used by BaseJobs, update only for Verify jobs */
372 if (jcr->getJobLevel() != L_FULL) {
379 be.set_errno(bfd->berrno);
380 Dmsg2(100, "Error reading file %s: ERR=%s\n", jcr->last_fname, be.bstrerror());
381 Jmsg(jcr, M_ERROR, 1, _("Error reading file %s: ERR=%s\n"),
382 jcr->last_fname, be.bstrerror());