2 Bacula® - The Network Backup Solution
4 Copyright (C) 2000-2007 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 John Walker.
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(FF_PKT *ff_pkt, void *my_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, (void *)jcr);
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(FF_PKT *ff_pkt, void *pkt, bool top_level)
76 char attribs[MAXSTRING];
77 char attribsEx[MAXSTRING];
78 int digest_stream = STREAM_NONE;
80 DIGEST *digest = NULL;
82 JCR *jcr = (JCR *)pkt;
84 if (job_canceled(jcr)) {
89 jcr->num_files_examined++; /* bump total file count */
91 switch (ff_pkt->type) {
92 case FT_LNKSAVED: /* Hard linked, file already saved */
93 Dmsg2(30, "FT_LNKSAVED saving: %s => %s\n", ff_pkt->fname, ff_pkt->link);
96 Dmsg1(30, "FT_REGE saving: %s\n", ff_pkt->fname);
99 Dmsg1(30, "FT_REG saving: %s\n", ff_pkt->fname);
102 Dmsg2(30, "FT_LNK saving: %s -> %s\n", ff_pkt->fname, ff_pkt->link);
105 jcr->num_files_examined--; /* correct file count */
106 return 1; /* ignored */
109 Dmsg1(30, "FT_DIR saving: %s\n", ff_pkt->fname);
112 Dmsg1(30, "FT_SPEC saving: %s\n", ff_pkt->fname);
115 Dmsg1(30, "FT_RAW saving: %s\n", ff_pkt->fname);
118 Dmsg1(30, "FT_FIFO saving: %s\n", ff_pkt->fname);
122 be.set_errno(ff_pkt->ff_errno);
123 Jmsg(jcr, M_NOTSAVED, 1, _(" Could not access %s: ERR=%s\n"), ff_pkt->fname, be.bstrerror());
129 be.set_errno(ff_pkt->ff_errno);
130 Jmsg(jcr, M_NOTSAVED, 1, _(" Could not follow link %s: ERR=%s\n"), ff_pkt->fname, be.bstrerror());
136 be.set_errno(ff_pkt->ff_errno);
137 Jmsg(jcr, M_NOTSAVED, 1, _(" Could not stat %s: ERR=%s\n"), ff_pkt->fname, be.bstrerror());
143 Jmsg(jcr, M_SKIPPED, 1, _(" Unchanged file skipped: %s\n"), ff_pkt->fname);
146 Jmsg(jcr, M_SKIPPED, 1, _(" Archive file skipped: %s\n"), ff_pkt->fname);
149 Jmsg(jcr, M_SKIPPED, 1, _(" Recursion turned off. Directory skipped: %s\n"), ff_pkt->fname);
150 ff_pkt->type = FT_DIREND; /* directory entry was backed up */
153 Jmsg(jcr, M_SKIPPED, 1, _(" File system change prohibited. Directory skipped: %s\n"), ff_pkt->fname);
157 be.set_errno(ff_pkt->ff_errno);
158 Jmsg(jcr, M_NOTSAVED, 1, _(" Could not open directory %s: ERR=%s\n"), ff_pkt->fname, be.bstrerror());
163 Jmsg(jcr, M_NOTSAVED, 0, _(" Unknown file type %d: %s\n"), ff_pkt->type, ff_pkt->fname);
168 /* Encode attributes and possibly extend them */
169 encode_stat(attribs, ff_pkt, 0);
170 encode_attribsEx(jcr, attribsEx, ff_pkt);
173 jcr->JobFiles++; /* increment number of files sent */
174 pm_strcpy(jcr->last_fname, ff_pkt->fname);
178 * Send file attributes to Director
182 * Filename (full path)
184 * Link name (if type==FT_LNK)
185 * For a directory, link is the same as fname, but with trailing
186 * slash. For a linked file, link is the link.
188 /* Send file attributes to Director (note different format than for Storage) */
189 Dmsg2(400, "send ATTR inx=%d fname=%s\n", jcr->JobFiles, ff_pkt->fname);
190 if (ff_pkt->type == FT_LNK || ff_pkt->type == FT_LNKSAVED) {
191 stat = bnet_fsend(dir, "%d %d %s %s%c%s%c%s%c", jcr->JobFiles,
192 STREAM_UNIX_ATTRIBUTES, ff_pkt->VerifyOpts, ff_pkt->fname,
193 0, attribs, 0, ff_pkt->link, 0);
194 } else if (ff_pkt->type == FT_DIREND || ff_pkt->type == FT_REPARSE) {
195 /* Here link is the canonical filename (i.e. with trailing slash) */
196 stat = bnet_fsend(dir,"%d %d %s %s%c%s%c%c", jcr->JobFiles,
197 STREAM_UNIX_ATTRIBUTES, ff_pkt->VerifyOpts, ff_pkt->link,
200 stat = bnet_fsend(dir,"%d %d %s %s%c%s%c%c", jcr->JobFiles,
201 STREAM_UNIX_ATTRIBUTES, ff_pkt->VerifyOpts, ff_pkt->fname,
204 Dmsg2(20, "bfiled>bdird: attribs len=%d: msg=%s\n", dir->msglen, dir->msg);
206 Jmsg(jcr, M_FATAL, 0, _("Network error in send to Director: ERR=%s\n"), bnet_strerror(dir));
211 * The remainder of the function is all about getting the checksum.
212 * First we initialise, then we read files, other streams and Finder Info.
214 if (ff_pkt->type != FT_LNKSAVED && (S_ISREG(ff_pkt->statp.st_mode) &&
215 ff_pkt->flags & (FO_MD5|FO_SHA1|FO_SHA256|FO_SHA512))) {
217 * Create our digest context. If this fails, the digest will be set to NULL
220 if (ff_pkt->flags & FO_MD5) {
221 digest = crypto_digest_new(jcr, CRYPTO_DIGEST_MD5);
222 digest_stream = STREAM_MD5_DIGEST;
224 } else if (ff_pkt->flags & FO_SHA1) {
225 digest = crypto_digest_new(jcr, CRYPTO_DIGEST_SHA1);
226 digest_stream = STREAM_SHA1_DIGEST;
228 } else if (ff_pkt->flags & FO_SHA256) {
229 digest = crypto_digest_new(jcr, CRYPTO_DIGEST_SHA256);
230 digest_stream = STREAM_SHA256_DIGEST;
232 } else if (ff_pkt->flags & FO_SHA512) {
233 digest = crypto_digest_new(jcr, CRYPTO_DIGEST_SHA512);
234 digest_stream = STREAM_SHA512_DIGEST;
237 /* Did digest initialization fail? */
238 if (digest_stream != STREAM_NONE && digest == NULL) {
239 Jmsg(jcr, M_WARNING, 0, _("%s digest initialization failed\n"),
240 stream_to_ascii(digest_stream));
243 /* compute MD5 or SHA1 hash */
245 char md[CRYPTO_DIGEST_MAX_SIZE];
250 if (digest_file(jcr, ff_pkt, digest) != 0) {
255 if (crypto_digest_finalize(digest, (uint8_t *)md, &size)) {
257 const char *digest_name;
259 digest_buf = (char *)malloc(BASE64_SIZE(size));
260 digest_name = crypto_digest_name(digest);
262 bin_to_base64(digest_buf, BASE64_SIZE(size), md, size, true);
263 Dmsg3(400, "send inx=%d %s=%s\n", jcr->JobFiles, digest_name, digest_buf);
264 bnet_fsend(dir, "%d %d %s *%s-%d*", jcr->JobFiles, digest_stream, digest_buf,
265 digest_name, jcr->JobFiles);
266 Dmsg3(20, "bfiled>bdird: %s len=%d: msg=%s\n", digest_name,
267 dir->msglen, dir->msg);
276 crypto_digest_free(digest);
282 * Compute message digest for the file specified by ff_pkt.
283 * In case of errors we need the job control record and file name.
285 int digest_file(JCR *jcr, FF_PKT *ff_pkt, DIGEST *digest)
289 Dmsg0(50, "=== digest_file\n");
292 if (ff_pkt->statp.st_size > 0 || ff_pkt->type == FT_RAW
293 || ff_pkt->type == FT_FIFO) {
294 int noatime = ff_pkt->flags & FO_NOATIME ? O_NOATIME : 0;
295 if ((bopen(&bfd, ff_pkt->fname, O_RDONLY | O_BINARY | noatime, 0)) < 0) {
296 ff_pkt->ff_errno = errno;
298 be.set_errno(bfd.berrno);
299 Dmsg2(100, "Cannot open %s: ERR=%s\n", ff_pkt->fname, be.bstrerror());
300 Jmsg(jcr, M_ERROR, 1, _(" Cannot open %s: ERR=%s.\n"),
301 ff_pkt->fname, be.bstrerror());
304 read_digest(&bfd, digest, jcr);
308 #ifdef HAVE_DARWIN_OS
309 /* Open resource fork if necessary */
310 if (ff_pkt->flags & FO_HFSPLUS && ff_pkt->hfsinfo.rsrclength > 0) {
311 if (bopen_rsrc(&bfd, ff_pkt->fname, O_RDONLY | O_BINARY, 0) < 0) {
312 ff_pkt->ff_errno = errno;
314 Jmsg(jcr, M_ERROR, -1, _(" Cannot open resource fork for %s: ERR=%s.\n"),
315 ff_pkt->fname, be.bstrerror());
316 if (is_bopen(&ff_pkt->bfd)) {
317 bclose(&ff_pkt->bfd);
321 read_digest(&bfd, digest, jcr);
325 if (digest && ff_pkt->flags & FO_HFSPLUS) {
326 crypto_digest_update(digest, (uint8_t *)ff_pkt->hfsinfo.fndrinfo, 32);
334 * Read message digest of bfd, updating digest
335 * In case of errors we need the job control record and file name.
337 int read_digest(BFILE *bfd, DIGEST *digest, JCR *jcr)
339 char buf[DEFAULT_NETWORK_BUFFER_SIZE];
342 Dmsg0(50, "=== read_digest\n");
343 while ((n=bread(bfd, buf, sizeof(buf))) > 0) {
344 crypto_digest_update(digest, (uint8_t *)buf, n);
350 be.set_errno(bfd->berrno);
351 Dmsg2(100, "Error reading file %s: ERR=%s\n", jcr->last_fname, be.bstrerror());
352 Jmsg(jcr, M_ERROR, 1, _("Error reading file %s: ERR=%s\n"),
353 jcr->last_fname, be.bstrerror());