]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/filed/verify.c
kes Start implementing bstrerror() in place of strerror().
[bacula/bacula] / bacula / src / filed / verify.c
1 /*
2    Bacula® - The Network Backup Solution
3
4    Copyright (C) 2000-2007 Free Software Foundation Europe e.V.
5
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 plus additions
11    that are listed in the file LICENSE.
12
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.
17
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
21    02110-1301, USA.
22
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.
27 */
28 /*
29  *  Bacula File Daemon  verify.c  Verify files.
30  *
31  *    Kern Sibbald, October MM
32  *
33  *   Version $Id$
34  *
35  */
36
37 #include "bacula.h"
38 #include "filed.h"
39
40 static int verify_file(FF_PKT *ff_pkt, void *my_pkt, bool);
41 static int read_digest(BFILE *bfd, DIGEST *digest, JCR *jcr);
42
43 /*
44  * Find all the requested files and send attributes
45  * to the Director.
46  *
47  */
48 void do_verify(JCR *jcr)
49 {
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);
55    }
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");
61
62    if (jcr->big_buf) {
63       free(jcr->big_buf);
64       jcr->big_buf = NULL;
65    }
66    set_jcr_job_status(jcr, JS_Terminated);
67 }
68
69 /*
70  * Called here by find() for each file.
71  *
72  *  Find the file, compute the MD5 or SHA1 and send it back to the Director
73  */
74 static int verify_file(FF_PKT *ff_pkt, void *pkt, bool top_level)
75 {
76    char attribs[MAXSTRING];
77    char attribsEx[MAXSTRING];
78    int digest_stream = STREAM_NONE;
79    int stat;
80    DIGEST *digest = NULL;
81    BSOCK *dir;
82    JCR *jcr = (JCR *)pkt;
83
84    if (job_canceled(jcr)) {
85       return 0;
86    }
87
88    dir = jcr->dir_bsock;
89    jcr->num_files_examined++;         /* bump total file count */
90
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);
94       break;
95    case FT_REGE:
96       Dmsg1(30, "FT_REGE saving: %s\n", ff_pkt->fname);
97       break;
98    case FT_REG:
99       Dmsg1(30, "FT_REG saving: %s\n", ff_pkt->fname);
100       break;
101    case FT_LNK:
102       Dmsg2(30, "FT_LNK saving: %s -> %s\n", ff_pkt->fname, ff_pkt->link);
103       break;
104    case FT_DIRBEGIN:
105       jcr->num_files_examined--;      /* correct file count */
106       return 1;                       /* ignored */
107    case FT_DIREND:
108       Dmsg1(30, "FT_DIR saving: %s\n", ff_pkt->fname);
109       break;
110    case FT_SPEC:
111       Dmsg1(30, "FT_SPEC saving: %s\n", ff_pkt->fname);
112       break;
113    case FT_RAW:
114       Dmsg1(30, "FT_RAW saving: %s\n", ff_pkt->fname);
115       break;
116    case FT_FIFO:
117       Dmsg1(30, "FT_FIFO saving: %s\n", ff_pkt->fname);
118       break;
119    case FT_NOACCESS: {
120       berrno be;
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());
123       jcr->Errors++;
124       return 1;
125    }
126    case FT_NOFOLLOW: {
127       berrno be;
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());
130       jcr->Errors++;
131       return 1;
132    }
133    case FT_NOSTAT: {
134       berrno be;
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());
137       jcr->Errors++;
138       return 1;
139    }
140    case FT_DIRNOCHG:
141    case FT_NOCHG:
142       Jmsg(jcr, M_SKIPPED, 1, _("     Unchanged file skipped: %s\n"), ff_pkt->fname);
143       return 1;
144    case FT_ISARCH:
145       Jmsg(jcr, M_SKIPPED, 1, _("     Archive file skipped: %s\n"), ff_pkt->fname);
146       return 1;
147    case FT_NORECURSE:
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 */
150       break;
151    case FT_NOFSCHG:
152       Jmsg(jcr, M_SKIPPED, 1, _("     File system change prohibited. Directory skipped: %s\n"), ff_pkt->fname);
153       return 1;
154    case FT_NOOPEN: {
155       berrno be;
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());
158       jcr->Errors++;
159       return 1;
160    }
161    default:
162       Jmsg(jcr, M_NOTSAVED, 0, _("     Unknown file type %d: %s\n"), ff_pkt->type, ff_pkt->fname);
163       jcr->Errors++;
164       return 1;
165    }
166
167    /* Encode attributes and possibly extend them */
168    encode_stat(attribs, ff_pkt, 0);
169    encode_attribsEx(jcr, attribsEx, ff_pkt);
170
171    jcr->lock();
172    jcr->JobFiles++;                  /* increment number of files sent */
173    pm_strcpy(jcr->last_fname, ff_pkt->fname);
174    jcr->unlock();
175
176    /*
177     * Send file attributes to Director
178     *   File_index
179     *   Stream
180     *   Verify Options
181     *   Filename (full path)
182     *   Encoded attributes
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.
186     */
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) {
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,
197                0, attribs, 0, 0);
198    } else {
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,
201             0, attribs, 0, 0);
202    }
203    Dmsg2(20, "bfiled>bdird: attribs len=%d: msg=%s\n", dir->msglen, dir->msg);
204    if (!stat) {
205       Jmsg(jcr, M_FATAL, 0, _("Network error in send to Director: ERR=%s\n"), bnet_strerror(dir));
206       return 0;
207    }
208
209    /*
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.
212     */
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))) {
215       /*
216        * Create our digest context. If this fails, the digest will be set to NULL
217        * and not used.
218        */
219       if (ff_pkt->flags & FO_MD5) {
220          digest = crypto_digest_new(jcr, CRYPTO_DIGEST_MD5);
221          digest_stream = STREAM_MD5_DIGEST;
222
223       } else if (ff_pkt->flags & FO_SHA1) {
224          digest = crypto_digest_new(jcr, CRYPTO_DIGEST_SHA1);
225          digest_stream = STREAM_SHA1_DIGEST;
226
227       } else if (ff_pkt->flags & FO_SHA256) {
228          digest = crypto_digest_new(jcr, CRYPTO_DIGEST_SHA256);
229          digest_stream = STREAM_SHA256_DIGEST;
230
231       } else if (ff_pkt->flags & FO_SHA512) {
232          digest = crypto_digest_new(jcr, CRYPTO_DIGEST_SHA512);
233          digest_stream = STREAM_SHA512_DIGEST;
234       }
235
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));
240       }
241
242       /* compute MD5 or SHA1 hash */
243       if (digest) {
244          char md[CRYPTO_DIGEST_MAX_SIZE];
245          uint32_t size;
246
247          size = sizeof(md);
248          
249          if (digest_file(jcr, ff_pkt, digest) != 0) {
250             jcr->Errors++;
251             goto good_rtn;
252          }
253
254          if (crypto_digest_finalize(digest, (uint8_t *)md, &size)) {
255             char *digest_buf;
256             const char *digest_name;
257             
258             digest_buf = (char *)malloc(BASE64_SIZE(size));
259             digest_name = crypto_digest_name(digest);
260
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);
267
268             free(digest_buf);
269          }
270       }
271    }
272
273 good_rtn:
274    if (digest) {
275       crypto_digest_free(digest);
276    }
277    return 1;
278 }
279
280 /*
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.
283  */
284 int digest_file(JCR *jcr, FF_PKT *ff_pkt, DIGEST *digest)
285 {
286    BFILE bfd;
287
288    Dmsg0(50, "=== digest_file\n");
289    binit(&bfd);
290
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;
296          berrno be;
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());
301          return 1;
302       }
303       read_digest(&bfd, digest, jcr);
304       bclose(&bfd);
305    }
306
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;
312          berrno be;
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);
317          }
318          return 1;
319       }
320       read_digest(&bfd, digest, jcr);
321       bclose(&bfd);
322    }
323
324    if (digest && ff_pkt->flags & FO_HFSPLUS) {
325       crypto_digest_update(digest, (uint8_t *)ff_pkt->hfsinfo.fndrinfo, 32);
326    }
327 #endif
328
329    return 0;
330 }
331
332 /*
333  * Read message digest of bfd, updating digest
334  * In case of errors we need the job control record and file name.
335  */
336 int read_digest(BFILE *bfd, DIGEST *digest, JCR *jcr)
337 {
338    char buf[DEFAULT_NETWORK_BUFFER_SIZE];
339    int64_t n;
340
341    Dmsg0(50, "=== read_digest\n");
342    while ((n=bread(bfd, buf, sizeof(buf))) > 0) {
343       crypto_digest_update(digest, (uint8_t *)buf, n);
344       jcr->JobBytes += n;
345       jcr->ReadBytes += n;
346    }
347    if (n < 0) {
348       berrno be;
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());
353       jcr->Errors++;
354       return -1;
355    }
356    return 0;
357 }