2 Bacula® - The Network Backup Solution
4 Copyright (C) 2000-2008 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
40 static int verify_file(JCR *jcr, FF_PKT *ff_pkt, bool);
41 static int read_digest(BFILE *bfd, DIGEST *digest, JCR *jcr);
44 * Find all the requested files and send attributes
48 void do_verify(JCR *jcr)
50 set_jcr_job_status(jcr, JS_Running);
51 jcr->buf_size = DEFAULT_NETWORK_BUFFER_SIZE;
52 if ((jcr->big_buf = (char *) malloc(jcr->buf_size)) == NULL) {
53 Jmsg1(jcr, M_ABORT, 0, _("Cannot malloc %d network read buffer\n"),
54 DEFAULT_NETWORK_BUFFER_SIZE);
56 set_find_options((FF_PKT *)jcr->ff, jcr->incremental, jcr->mtime);
57 Dmsg0(10, "Start find files\n");
58 /* Subroutine verify_file() is called for each file */
59 find_files(jcr, (FF_PKT *)jcr->ff, verify_file, NULL);
60 Dmsg0(10, "End find files\n");
66 set_jcr_job_status(jcr, JS_Terminated);
70 * Called here by find() for each file.
72 * Find the file, compute the MD5 or SHA1 and send it back to the Director
74 static int verify_file(JCR *jcr, FF_PKT *ff_pkt, bool top_level)
76 char attribs[MAXSTRING];
77 char attribsEx[MAXSTRING];
78 int digest_stream = STREAM_NONE;
80 DIGEST *digest = NULL;
83 if (job_canceled(jcr)) {
88 jcr->num_files_examined++; /* bump total file count */
90 switch (ff_pkt->type) {
91 case FT_LNKSAVED: /* Hard linked, file already saved */
92 Dmsg2(30, "FT_LNKSAVED saving: %s => %s\n", ff_pkt->fname, ff_pkt->link);
95 Dmsg1(30, "FT_REGE saving: %s\n", ff_pkt->fname);
98 Dmsg1(30, "FT_REG saving: %s\n", ff_pkt->fname);
101 Dmsg2(30, "FT_LNK saving: %s -> %s\n", ff_pkt->fname, ff_pkt->link);
104 jcr->num_files_examined--; /* correct file count */
105 return 1; /* ignored */
108 Dmsg1(30, "FT_DIR saving: %s\n", ff_pkt->fname);
111 Dmsg1(30, "FT_SPEC saving: %s\n", ff_pkt->fname);
114 Dmsg1(30, "FT_RAW saving: %s\n", ff_pkt->fname);
117 Dmsg1(30, "FT_FIFO saving: %s\n", ff_pkt->fname);
121 be.set_errno(ff_pkt->ff_errno);
122 Jmsg(jcr, M_NOTSAVED, 1, _(" Could not access %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 follow link %s: ERR=%s\n"), ff_pkt->fname, be.bstrerror());
135 be.set_errno(ff_pkt->ff_errno);
136 Jmsg(jcr, M_NOTSAVED, 1, _(" Could not stat %s: ERR=%s\n"), ff_pkt->fname, be.bstrerror());
142 Jmsg(jcr, M_SKIPPED, 1, _(" Unchanged file skipped: %s\n"), ff_pkt->fname);
145 Jmsg(jcr, M_SKIPPED, 1, _(" Archive file skipped: %s\n"), ff_pkt->fname);
148 Jmsg(jcr, M_SKIPPED, 1, _(" Recursion turned off. Directory skipped: %s\n"), ff_pkt->fname);
149 ff_pkt->type = FT_DIREND; /* directory entry was backed up */
152 Jmsg(jcr, M_SKIPPED, 1, _(" File system change prohibited. Directory skipped: %s\n"), ff_pkt->fname);
156 be.set_errno(ff_pkt->ff_errno);
157 Jmsg(jcr, M_NOTSAVED, 1, _(" Could not open directory %s: ERR=%s\n"), ff_pkt->fname, be.bstrerror());
162 Jmsg(jcr, M_NOTSAVED, 0, _(" Unknown file type %d: %s\n"), ff_pkt->type, ff_pkt->fname);
167 /* Encode attributes and possibly extend them */
168 encode_stat(attribs, ff_pkt, 0);
169 encode_attribsEx(jcr, attribsEx, ff_pkt);
172 jcr->JobFiles++; /* increment number of files sent */
173 pm_strcpy(jcr->last_fname, ff_pkt->fname);
177 * Send file attributes to Director
181 * Filename (full path)
183 * Link name (if type==FT_LNK)
184 * For a directory, link is the same as fname, but with trailing
185 * slash. For a linked file, link is the link.
187 /* Send file attributes to Director (note different format than for Storage) */
188 Dmsg2(400, "send ATTR inx=%d fname=%s\n", jcr->JobFiles, ff_pkt->fname);
189 if (ff_pkt->type == FT_LNK || ff_pkt->type == FT_LNKSAVED) {
190 stat = bnet_fsend(dir, "%d %d %s %s%c%s%c%s%c", jcr->JobFiles,
191 STREAM_UNIX_ATTRIBUTES, ff_pkt->VerifyOpts, ff_pkt->fname,
192 0, attribs, 0, ff_pkt->link, 0);
193 } else if (ff_pkt->type == FT_DIREND || ff_pkt->type == FT_REPARSE) {
194 /* Here link is the canonical filename (i.e. with trailing slash) */
195 stat = bnet_fsend(dir,"%d %d %s %s%c%s%c%c", jcr->JobFiles,
196 STREAM_UNIX_ATTRIBUTES, ff_pkt->VerifyOpts, ff_pkt->link,
199 stat = bnet_fsend(dir,"%d %d %s %s%c%s%c%c", jcr->JobFiles,
200 STREAM_UNIX_ATTRIBUTES, ff_pkt->VerifyOpts, ff_pkt->fname,
203 Dmsg2(20, "bfiled>bdird: attribs len=%d: msg=%s\n", dir->msglen, dir->msg);
205 Jmsg(jcr, M_FATAL, 0, _("Network error in send to Director: ERR=%s\n"), bnet_strerror(dir));
210 * The remainder of the function is all about getting the checksum.
211 * First we initialise, then we read files, other streams and Finder Info.
213 if (ff_pkt->type != FT_LNKSAVED && (S_ISREG(ff_pkt->statp.st_mode) &&
214 ff_pkt->flags & (FO_MD5|FO_SHA1|FO_SHA256|FO_SHA512))) {
216 * Create our digest context. If this fails, the digest will be set to NULL
219 if (ff_pkt->flags & FO_MD5) {
220 digest = crypto_digest_new(jcr, CRYPTO_DIGEST_MD5);
221 digest_stream = STREAM_MD5_DIGEST;
223 } else if (ff_pkt->flags & FO_SHA1) {
224 digest = crypto_digest_new(jcr, CRYPTO_DIGEST_SHA1);
225 digest_stream = STREAM_SHA1_DIGEST;
227 } else if (ff_pkt->flags & FO_SHA256) {
228 digest = crypto_digest_new(jcr, CRYPTO_DIGEST_SHA256);
229 digest_stream = STREAM_SHA256_DIGEST;
231 } else if (ff_pkt->flags & FO_SHA512) {
232 digest = crypto_digest_new(jcr, CRYPTO_DIGEST_SHA512);
233 digest_stream = STREAM_SHA512_DIGEST;
236 /* Did digest initialization fail? */
237 if (digest_stream != STREAM_NONE && digest == NULL) {
238 Jmsg(jcr, M_WARNING, 0, _("%s digest initialization failed\n"),
239 stream_to_ascii(digest_stream));
242 /* compute MD5 or SHA1 hash */
244 char md[CRYPTO_DIGEST_MAX_SIZE];
249 if (digest_file(jcr, ff_pkt, digest) != 0) {
254 if (crypto_digest_finalize(digest, (uint8_t *)md, &size)) {
256 const char *digest_name;
258 digest_buf = (char *)malloc(BASE64_SIZE(size));
259 digest_name = crypto_digest_name(digest);
261 bin_to_base64(digest_buf, BASE64_SIZE(size), md, size, true);
262 Dmsg3(400, "send inx=%d %s=%s\n", jcr->JobFiles, digest_name, digest_buf);
263 bnet_fsend(dir, "%d %d %s *%s-%d*", jcr->JobFiles, digest_stream, digest_buf,
264 digest_name, jcr->JobFiles);
265 Dmsg3(20, "bfiled>bdird: %s len=%d: msg=%s\n", digest_name,
266 dir->msglen, dir->msg);
275 crypto_digest_free(digest);
281 * Compute message digest for the file specified by ff_pkt.
282 * In case of errors we need the job control record and file name.
284 int digest_file(JCR *jcr, FF_PKT *ff_pkt, DIGEST *digest)
288 Dmsg0(50, "=== digest_file\n");
291 if (ff_pkt->statp.st_size > 0 || ff_pkt->type == FT_RAW
292 || ff_pkt->type == FT_FIFO) {
293 int noatime = ff_pkt->flags & FO_NOATIME ? O_NOATIME : 0;
294 if ((bopen(&bfd, ff_pkt->fname, O_RDONLY | O_BINARY | noatime, 0)) < 0) {
295 ff_pkt->ff_errno = errno;
297 be.set_errno(bfd.berrno);
298 Dmsg2(100, "Cannot open %s: ERR=%s\n", ff_pkt->fname, be.bstrerror());
299 Jmsg(jcr, M_ERROR, 1, _(" Cannot open %s: ERR=%s.\n"),
300 ff_pkt->fname, be.bstrerror());
303 read_digest(&bfd, digest, jcr);
307 #ifdef HAVE_DARWIN_OS
308 /* Open resource fork if necessary */
309 if (ff_pkt->flags & FO_HFSPLUS && ff_pkt->hfsinfo.rsrclength > 0) {
310 if (bopen_rsrc(&bfd, ff_pkt->fname, O_RDONLY | O_BINARY, 0) < 0) {
311 ff_pkt->ff_errno = errno;
313 Jmsg(jcr, M_ERROR, -1, _(" Cannot open resource fork for %s: ERR=%s.\n"),
314 ff_pkt->fname, be.bstrerror());
315 if (is_bopen(&ff_pkt->bfd)) {
316 bclose(&ff_pkt->bfd);
320 read_digest(&bfd, digest, jcr);
324 if (digest && ff_pkt->flags & FO_HFSPLUS) {
325 crypto_digest_update(digest, (uint8_t *)ff_pkt->hfsinfo.fndrinfo, 32);
333 * Read message digest of bfd, updating digest
334 * In case of errors we need the job control record and file name.
336 int read_digest(BFILE *bfd, DIGEST *digest, JCR *jcr)
338 char buf[DEFAULT_NETWORK_BUFFER_SIZE];
341 Dmsg0(50, "=== read_digest\n");
342 while ((n=bread(bfd, buf, sizeof(buf))) > 0) {
343 crypto_digest_update(digest, (uint8_t *)buf, n);
349 be.set_errno(bfd->berrno);
350 Dmsg2(100, "Error reading file %s: ERR=%s\n", jcr->last_fname, be.bstrerror());
351 Jmsg(jcr, M_ERROR, 1, _("Error reading file %s: ERR=%s\n"),
352 jcr->last_fname, be.bstrerror());