2 Bacula® - The Network Backup Solution
4 Copyright (C) 2000-2014 Free Software Foundation Europe e.V.
6 The main author of Bacula is Kern Sibbald, with contributions from many
7 others, a complete list can be found in the file AUTHORS.
9 You may use this file and others of this release according to the
10 license defined in the LICENSE file, which includes the Affero General
11 Public License, v3.0 ("AGPLv3") and some additional permissions and
12 terms pursuant to its AGPLv3 Section 7.
14 Bacula® is a registered trademark of Kern Sibbald.
17 * Bacula File Daemon verify.c Verify files.
19 * Kern Sibbald, October MM
27 const bool have_darwin_os = true;
29 const bool have_darwin_os = false;
32 static int verify_file(JCR *jcr, FF_PKT *ff_pkt, bool);
33 static int read_digest(BFILE *bfd, DIGEST *digest, JCR *jcr);
36 * Find all the requested files and send attributes
40 void do_verify(JCR *jcr)
42 jcr->setJobStatus(JS_Running);
43 jcr->buf_size = DEFAULT_NETWORK_BUFFER_SIZE;
44 if ((jcr->big_buf = (char *) malloc(jcr->buf_size)) == NULL) {
45 Jmsg1(jcr, M_ABORT, 0, _("Cannot malloc %d network read buffer\n"),
46 DEFAULT_NETWORK_BUFFER_SIZE);
48 set_find_options((FF_PKT *)jcr->ff, jcr->incremental, jcr->mtime);
49 Dmsg0(10, "Start find files\n");
50 /* Subroutine verify_file() is called for each file */
51 find_files(jcr, (FF_PKT *)jcr->ff, verify_file, NULL);
52 Dmsg0(10, "End find files\n");
58 jcr->setJobStatus(JS_Terminated);
62 * Called here by find() for each file.
64 * Find the file, compute the MD5 or SHA1 and send it back to the Director
66 static int verify_file(JCR *jcr, FF_PKT *ff_pkt, bool top_level)
68 char attribs[MAXSTRING];
69 char attribsEx[MAXSTRING];
70 int digest_stream = STREAM_NONE;
72 DIGEST *digest = NULL;
75 if (job_canceled(jcr)) {
80 jcr->num_files_examined++; /* bump total file count */
82 switch (ff_pkt->type) {
83 case FT_LNKSAVED: /* Hard linked, file already saved */
84 Dmsg2(30, "FT_LNKSAVED saving: %s => %s\n", ff_pkt->fname, ff_pkt->link);
87 Dmsg1(30, "FT_REGE saving: %s\n", ff_pkt->fname);
90 Dmsg1(30, "FT_REG saving: %s\n", ff_pkt->fname);
93 Dmsg2(30, "FT_LNK saving: %s -> %s\n", ff_pkt->fname, ff_pkt->link);
96 jcr->num_files_examined--; /* correct file count */
97 return 1; /* ignored */
101 Dmsg1(30, "FT_DIR saving: %s\n", ff_pkt->fname);
104 Dmsg1(30, "FT_SPEC saving: %s\n", ff_pkt->fname);
107 Dmsg1(30, "FT_RAW saving: %s\n", ff_pkt->fname);
110 Dmsg1(30, "FT_FIFO saving: %s\n", ff_pkt->fname);
114 be.set_errno(ff_pkt->ff_errno);
115 Jmsg(jcr, M_NOTSAVED, 1, _(" Could not access %s: ERR=%s\n"), ff_pkt->fname, be.bstrerror());
121 be.set_errno(ff_pkt->ff_errno);
122 Jmsg(jcr, M_NOTSAVED, 1, _(" Could not follow link %s: ERR=%s\n"), ff_pkt->fname, be.bstrerror());
128 be.set_errno(ff_pkt->ff_errno);
129 Jmsg(jcr, M_NOTSAVED, 1, _(" Could not stat %s: ERR=%s\n"), ff_pkt->fname, be.bstrerror());
135 Jmsg(jcr, M_SKIPPED, 1, _(" Unchanged file skipped: %s\n"), ff_pkt->fname);
138 Jmsg(jcr, M_SKIPPED, 1, _(" Archive file skipped: %s\n"), ff_pkt->fname);
141 Jmsg(jcr, M_SKIPPED, 1, _(" Recursion turned off. Directory skipped: %s\n"), ff_pkt->fname);
142 ff_pkt->type = FT_DIREND; /* directory entry was backed up */
145 Jmsg(jcr, M_SKIPPED, 1, _(" File system change prohibited. Directory skipped: %s\n"), ff_pkt->fname);
147 case FT_PLUGIN_CONFIG:
148 case FT_RESTORE_FIRST:
149 return 1; /* silently skip */
152 be.set_errno(ff_pkt->ff_errno);
153 Jmsg(jcr, M_NOTSAVED, 1, _(" Could not open directory %s: ERR=%s\n"), ff_pkt->fname, be.bstrerror());
158 Jmsg(jcr, M_NOTSAVED, 0, _(" Unknown file type %d: %s\n"), ff_pkt->type, ff_pkt->fname);
163 /* Encode attributes and possibly extend them */
164 encode_stat(attribs, &ff_pkt->statp, sizeof(ff_pkt->statp), ff_pkt->LinkFI, 0);
165 encode_attribsEx(jcr, attribsEx, ff_pkt);
168 jcr->JobFiles++; /* increment number of files sent */
169 pm_strcpy(jcr->last_fname, ff_pkt->fname);
173 * Send file attributes to Director
177 * Filename (full path)
179 * Link name (if type==FT_LNK)
180 * For a directory, link is the same as fname, but with trailing
181 * slash. For a linked file, link is the link.
183 /* Send file attributes to Director (note different format than for Storage) */
184 Dmsg2(400, "send ATTR inx=%d fname=%s\n", jcr->JobFiles, ff_pkt->fname);
185 if (ff_pkt->type == FT_LNK || ff_pkt->type == FT_LNKSAVED) {
186 stat = dir->fsend("%d %d %s %s%c%s%c%s%c", jcr->JobFiles,
187 STREAM_UNIX_ATTRIBUTES, ff_pkt->VerifyOpts, ff_pkt->fname,
188 0, attribs, 0, ff_pkt->link, 0);
189 } else if (ff_pkt->type == FT_DIREND || ff_pkt->type == FT_REPARSE ||
190 ff_pkt->type == FT_JUNCTION) {
191 /* Here link is the canonical filename (i.e. with trailing slash) */
192 stat = dir->fsend("%d %d %s %s%c%s%c%c", jcr->JobFiles,
193 STREAM_UNIX_ATTRIBUTES, ff_pkt->VerifyOpts, ff_pkt->link,
196 stat = dir->fsend("%d %d %s %s%c%s%c%c", jcr->JobFiles,
197 STREAM_UNIX_ATTRIBUTES, ff_pkt->VerifyOpts, ff_pkt->fname,
200 Dmsg2(20, "bfiled>bdird: attribs len=%d: msg=%s\n", dir->msglen, dir->msg);
202 Jmsg(jcr, M_FATAL, 0, _("Network error in send to Director: ERR=%s\n"), dir->bstrerror());
207 * The remainder of the function is all about getting the checksum.
208 * First we initialise, then we read files, other streams and Finder Info.
210 if (ff_pkt->type != FT_LNKSAVED && (S_ISREG(ff_pkt->statp.st_mode) &&
211 ff_pkt->flags & (FO_MD5|FO_SHA1|FO_SHA256|FO_SHA512))) {
213 * Create our digest context. If this fails, the digest will be set to NULL
216 if (ff_pkt->flags & FO_MD5) {
217 digest = crypto_digest_new(jcr, CRYPTO_DIGEST_MD5);
218 digest_stream = STREAM_MD5_DIGEST;
220 } else if (ff_pkt->flags & FO_SHA1) {
221 digest = crypto_digest_new(jcr, CRYPTO_DIGEST_SHA1);
222 digest_stream = STREAM_SHA1_DIGEST;
224 } else if (ff_pkt->flags & FO_SHA256) {
225 digest = crypto_digest_new(jcr, CRYPTO_DIGEST_SHA256);
226 digest_stream = STREAM_SHA256_DIGEST;
228 } else if (ff_pkt->flags & FO_SHA512) {
229 digest = crypto_digest_new(jcr, CRYPTO_DIGEST_SHA512);
230 digest_stream = STREAM_SHA512_DIGEST;
233 /* Did digest initialization fail? */
234 if (digest_stream != STREAM_NONE && digest == NULL) {
235 Jmsg(jcr, M_WARNING, 0, _("%s digest initialization failed\n"),
236 stream_to_ascii(digest_stream));
239 /* compute MD5 or SHA1 hash */
241 char md[CRYPTO_DIGEST_MAX_SIZE];
246 if (digest_file(jcr, ff_pkt, digest) != 0) {
251 if (crypto_digest_finalize(digest, (uint8_t *)md, &size)) {
253 const char *digest_name;
255 digest_buf = (char *)malloc(BASE64_SIZE(size));
256 digest_name = crypto_digest_name(digest);
258 bin_to_base64(digest_buf, BASE64_SIZE(size), md, size, true);
259 Dmsg3(400, "send inx=%d %s=%s\n", jcr->JobFiles, digest_name, digest_buf);
260 dir->fsend("%d %d %s *%s-%d*", jcr->JobFiles, digest_stream, digest_buf,
261 digest_name, jcr->JobFiles);
262 Dmsg3(20, "bfiled>bdird: %s len=%d: msg=%s\n", digest_name,
263 dir->msglen, dir->msg);
272 crypto_digest_free(digest);
278 * Compute message digest for the file specified by ff_pkt.
279 * In case of errors we need the job control record and file name.
281 int digest_file(JCR *jcr, FF_PKT *ff_pkt, DIGEST *digest)
285 Dmsg0(50, "=== digest_file\n");
288 if (ff_pkt->statp.st_size > 0 ||
289 ff_pkt->type == FT_RAW ||
290 ff_pkt->type == FT_FIFO) {
291 int noatime = ff_pkt->flags & FO_NOATIME ? O_NOATIME : 0;
292 if ((bopen(&bfd, ff_pkt->fname, O_RDONLY | O_BINARY | noatime, 0)) < 0) {
293 ff_pkt->ff_errno = errno;
295 be.set_errno(bfd.berrno);
296 Dmsg2(100, "Cannot open %s: ERR=%s\n", ff_pkt->fname, be.bstrerror());
297 Jmsg(jcr, M_ERROR, 1, _(" Cannot open %s: ERR=%s.\n"),
298 ff_pkt->fname, be.bstrerror());
301 read_digest(&bfd, digest, jcr);
305 if (have_darwin_os) {
306 /* Open resource fork if necessary */
307 if (ff_pkt->flags & FO_HFSPLUS && ff_pkt->hfsinfo.rsrclength > 0) {
308 if (bopen_rsrc(&bfd, ff_pkt->fname, O_RDONLY | O_BINARY, 0) < 0) {
309 ff_pkt->ff_errno = errno;
311 Jmsg(jcr, M_ERROR, -1, _(" Cannot open resource fork for %s: ERR=%s.\n"),
312 ff_pkt->fname, be.bstrerror());
313 if (is_bopen(&ff_pkt->bfd)) {
314 bclose(&ff_pkt->bfd);
318 read_digest(&bfd, digest, jcr);
322 if (digest && ff_pkt->flags & FO_HFSPLUS) {
323 crypto_digest_update(digest, (uint8_t *)ff_pkt->hfsinfo.fndrinfo, 32);
330 * Read message digest of bfd, updating digest
331 * In case of errors we need the job control record and file name.
333 static int read_digest(BFILE *bfd, DIGEST *digest, JCR *jcr)
335 char buf[DEFAULT_NETWORK_BUFFER_SIZE];
337 int64_t bufsiz = (int64_t)sizeof(buf);
338 FF_PKT *ff_pkt = (FF_PKT *)jcr->ff;
339 uint64_t fileAddr = 0; /* file address */
342 Dmsg0(50, "=== read_digest\n");
343 while ((n=bread(bfd, buf, bufsiz)) > 0) {
344 /* Check for sparse blocks */
345 if (ff_pkt->flags & FO_SPARSE) {
346 bool allZeros = false;
348 fileAddr+n < (uint64_t)ff_pkt->statp.st_size) ||
349 ((ff_pkt->type == FT_RAW || ff_pkt->type == FT_FIFO) &&
350 (uint64_t)ff_pkt->statp.st_size == 0)) {
351 allZeros = is_buf_zero(buf, bufsiz);
353 fileAddr += n; /* update file address */
354 /* Skip any block of all zeros */
356 continue; /* skip block of zeros */
360 crypto_digest_update(digest, (uint8_t *)buf, n);
362 /* Can be used by BaseJobs or with accurate, update only for Verify
365 if (jcr->getJobType() == JT_VERIFY) {
372 be.set_errno(bfd->berrno);
373 Dmsg2(100, "Error reading file %s: ERR=%s\n", jcr->last_fname, be.bstrerror());
374 Jmsg(jcr, M_ERROR, 1, _("Error reading file %s: ERR=%s\n"),
375 jcr->last_fname, be.bstrerror());