2 * Bacula File Daemon verify.c Verify files.
4 * Kern Sibbald, October MM
10 Bacula® - The Network Backup Solution
12 Copyright (C) 2000-2006 Free Software Foundation Europe e.V.
14 The main author of Bacula is Kern Sibbald, with contributions from
15 many others, a complete list can be found in the file AUTHORS.
16 This program is Free Software; you can redistribute it and/or
17 modify it under the terms of version two of the GNU General Public
18 License as published by the Free Software Foundation plus additions
19 that are listed in the file LICENSE.
21 This program is distributed in the hope that it will be useful, but
22 WITHOUT ANY WARRANTY; without even the implied warranty of
23 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
24 General Public License for more details.
26 You should have received a copy of the GNU General Public License
27 along with this program; if not, write to the Free Software
28 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
31 Bacula® is a registered trademark of John Walker.
32 The licensor of Bacula is the Free Software Foundation Europe
33 (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
34 Switzerland, email:ftf@fsfeurope.org.
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 return 1; /* ignored */
107 Dmsg1(30, "FT_DIR saving: %s\n", ff_pkt->fname);
110 Dmsg1(30, "FT_SPEC saving: %s\n", ff_pkt->fname);
113 Dmsg1(30, "FT_RAW saving: %s\n", ff_pkt->fname);
116 Dmsg1(30, "FT_FIFO saving: %s\n", ff_pkt->fname);
120 be.set_errno(ff_pkt->ff_errno);
121 Jmsg(jcr, M_NOTSAVED, 1, _(" Could not access %s: ERR=%s\n"), ff_pkt->fname, be.strerror());
127 be.set_errno(ff_pkt->ff_errno);
128 Jmsg(jcr, M_NOTSAVED, 1, _(" Could not follow link %s: ERR=%s\n"), ff_pkt->fname, be.strerror());
134 be.set_errno(ff_pkt->ff_errno);
135 Jmsg(jcr, M_NOTSAVED, 1, _(" Could not stat %s: ERR=%s\n"), ff_pkt->fname, be.strerror());
141 Jmsg(jcr, M_SKIPPED, 1, _(" Unchanged file skipped: %s\n"), ff_pkt->fname);
144 Jmsg(jcr, M_SKIPPED, 1, _(" Archive file skipped: %s\n"), ff_pkt->fname);
147 Jmsg(jcr, M_SKIPPED, 1, _(" Recursion turned off. Directory skipped: %s\n"), ff_pkt->fname);
150 Jmsg(jcr, M_SKIPPED, 1, _(" File system change prohibited. Directory skipped: %s\n"), ff_pkt->fname);
154 be.set_errno(ff_pkt->ff_errno);
155 Jmsg(jcr, M_NOTSAVED, 1, _(" Could not open directory %s: ERR=%s\n"), ff_pkt->fname, be.strerror());
160 Jmsg(jcr, M_NOTSAVED, 0, _(" Unknown file type %d: %s\n"), ff_pkt->type, ff_pkt->fname);
165 /* Encode attributes and possibly extend them */
166 encode_stat(attribs, ff_pkt, 0);
167 encode_attribsEx(jcr, attribsEx, ff_pkt);
170 jcr->JobFiles++; /* increment number of files sent */
171 pm_strcpy(jcr->last_fname, ff_pkt->fname);
175 * Send file attributes to Director
179 * Filename (full path)
181 * Link name (if type==FT_LNK)
182 * For a directory, link is the same as fname, but with trailing
183 * slash. For a linked file, link is the link.
185 /* Send file attributes to Director (note different format than for Storage) */
186 Dmsg2(400, "send ATTR inx=%d fname=%s\n", jcr->JobFiles, ff_pkt->fname);
187 if (ff_pkt->type == FT_LNK || ff_pkt->type == FT_LNKSAVED) {
188 stat = bnet_fsend(dir, "%d %d %s %s%c%s%c%s%c", jcr->JobFiles,
189 STREAM_UNIX_ATTRIBUTES, ff_pkt->VerifyOpts, ff_pkt->fname,
190 0, attribs, 0, ff_pkt->link, 0);
191 } else if (ff_pkt->type == FT_DIREND) {
192 /* Here link is the canonical filename (i.e. with trailing slash) */
193 stat = bnet_fsend(dir,"%d %d %s %s%c%s%c%c", jcr->JobFiles,
194 STREAM_UNIX_ATTRIBUTES, ff_pkt->VerifyOpts, ff_pkt->link,
197 stat = bnet_fsend(dir,"%d %d %s %s%c%s%c%c", jcr->JobFiles,
198 STREAM_UNIX_ATTRIBUTES, ff_pkt->VerifyOpts, ff_pkt->fname,
201 Dmsg2(20, "bfiled>bdird: attribs len=%d: msg=%s\n", dir->msglen, dir->msg);
203 Jmsg(jcr, M_FATAL, 0, _("Network error in send to Director: ERR=%s\n"), bnet_strerror(dir));
208 * The remainder of the function is all about getting the checksum.
209 * First we initialise, then we read files, other streams and Finder Info.
211 if (ff_pkt->type != FT_LNKSAVED && (S_ISREG(ff_pkt->statp.st_mode) &&
212 ff_pkt->flags & (FO_MD5|FO_SHA1|FO_SHA256|FO_SHA512))) {
214 * Create our digest context. If this fails, the digest will be set to NULL
217 if (ff_pkt->flags & FO_MD5) {
218 digest = crypto_digest_new(CRYPTO_DIGEST_MD5);
219 digest_stream = STREAM_MD5_DIGEST;
221 } else if (ff_pkt->flags & FO_SHA1) {
222 digest = crypto_digest_new(CRYPTO_DIGEST_SHA1);
223 digest_stream = STREAM_SHA1_DIGEST;
225 } else if (ff_pkt->flags & FO_SHA256) {
226 digest = crypto_digest_new(CRYPTO_DIGEST_SHA256);
227 digest_stream = STREAM_SHA256_DIGEST;
229 } else if (ff_pkt->flags & FO_SHA512) {
230 digest = crypto_digest_new(CRYPTO_DIGEST_SHA512);
231 digest_stream = STREAM_SHA512_DIGEST;
234 /* Did digest initialization fail? */
235 if (digest_stream != STREAM_NONE && digest == NULL) {
236 Jmsg(jcr, M_WARNING, 0, _("%s digest initialization failed\n"),
237 stream_to_ascii(digest_stream));
240 /* compute MD5 or SHA1 hash */
242 char md[CRYPTO_DIGEST_MAX_SIZE];
247 if (digest_file(jcr, ff_pkt, digest) != 0) {
252 if (crypto_digest_finalize(digest, (uint8_t *)md, &size)) {
254 const char *digest_name;
256 digest_buf = (char *)malloc(BASE64_SIZE(size));
257 digest_name = crypto_digest_name(digest);
259 bin_to_base64(digest_buf, BASE64_SIZE(size), md, size, true);
260 Dmsg3(400, "send inx=%d %s=%s\n", jcr->JobFiles, digest_name, digest_buf);
261 bnet_fsend(dir, "%d %d %s *%s-%d*", jcr->JobFiles, digest_stream, digest_buf,
262 digest_name, jcr->JobFiles);
263 Dmsg3(20, "bfiled>bdird: %s len=%d: msg=%s\n", digest_name,
264 dir->msglen, dir->msg);
269 crypto_digest_free(digest);
277 * Compute message digest for the file specified by ff_pkt.
278 * In case of errors we need the job control record and file name.
280 int digest_file(JCR *jcr, FF_PKT *ff_pkt, DIGEST *digest)
286 if (ff_pkt->statp.st_size > 0 || ff_pkt->type == FT_RAW
287 || ff_pkt->type == FT_FIFO) {
288 int noatime = ff_pkt->flags & FO_NOATIME ? O_NOATIME : 0;
289 if ((bopen(&bfd, ff_pkt->fname, O_RDONLY | O_BINARY | noatime, 0)) < 0) {
290 ff_pkt->ff_errno = errno;
292 be.set_errno(bfd.berrno);
293 Jmsg(jcr, M_NOTSAVED, 1, _(" Cannot open %s: ERR=%s.\n"),
294 ff_pkt->fname, be.strerror());
297 read_digest(&bfd, digest, jcr);
301 #ifdef HAVE_DARWIN_OS
302 /* Open resource fork if necessary */
303 if (ff_pkt->flags & FO_HFSPLUS && ff_pkt->hfsinfo.rsrclength > 0) {
304 if (bopen_rsrc(&bfd, ff_pkt->fname, O_RDONLY | O_BINARY, 0) < 0) {
305 ff_pkt->ff_errno = errno;
307 Jmsg(jcr, M_NOTSAVED, -1, _(" Cannot open resource fork for %s: ERR=%s.\n"),
308 ff_pkt->fname, be.strerror());
309 if (is_bopen(&ff_pkt->bfd)) {
310 bclose(&ff_pkt->bfd);
314 read_digest(&bfd, digest, jcr);
318 if (digest && ff_pkt->flags & FO_HFSPLUS) {
319 crypto_digest_update(digest, (uint8_t *)ff_pkt->hfsinfo.fndrinfo, 32);
327 * Read message digest of bfd, updating digest
328 * In case of errors we need the job control record and file name.
330 int read_digest(BFILE *bfd, DIGEST *digest, JCR *jcr)
332 char buf[DEFAULT_NETWORK_BUFFER_SIZE];
335 while ((n=bread(bfd, buf, sizeof(buf))) > 0) {
336 crypto_digest_update(digest, (uint8_t *)buf, n);
342 be.set_errno(bfd->berrno);
343 Jmsg(jcr, M_ERROR, 1, _("Error reading file %s: ERR=%s\n"),
344 jcr->last_fname, be.strerror());