]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/filed/verify.c
14a667106db7d4c38de28f1b46615912b05b8dd8
[bacula/bacula] / bacula / src / filed / verify.c
1 /*
2  *  Bacula File Daemon  verify.c  Verify files.
3  *
4  *    Kern Sibbald, October MM
5  *
6  *   Version $Id$
7  *
8  */
9 /*
10    Bacula® - The Network Backup Solution
11
12    Copyright (C) 2000-2006 Free Software Foundation Europe e.V.
13
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.
20
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.
25
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
29    02110-1301, USA.
30
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.
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       return 1;                       /* ignored */
106    case FT_DIREND:
107       Dmsg1(30, "FT_DIR saving: %s\n", ff_pkt->fname);
108       break;
109    case FT_SPEC:
110       Dmsg1(30, "FT_SPEC saving: %s\n", ff_pkt->fname);
111       break;
112    case FT_RAW:
113       Dmsg1(30, "FT_RAW saving: %s\n", ff_pkt->fname);
114       break;
115    case FT_FIFO:
116       Dmsg1(30, "FT_FIFO saving: %s\n", ff_pkt->fname);
117       break;
118    case FT_NOACCESS: {
119       berrno be;
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());
122       jcr->Errors++;
123       return 1;
124    }
125    case FT_NOFOLLOW: {
126       berrno be;
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());
129       jcr->Errors++;
130       return 1;
131    }
132    case FT_NOSTAT: {
133       berrno be;
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());
136       jcr->Errors++;
137       return 1;
138    }
139    case FT_DIRNOCHG:
140    case FT_NOCHG:
141       Jmsg(jcr, M_SKIPPED, 1, _("     Unchanged file skipped: %s\n"), ff_pkt->fname);
142       return 1;
143    case FT_ISARCH:
144       Jmsg(jcr, M_SKIPPED, 1, _("     Archive file skipped: %s\n"), ff_pkt->fname);
145       return 1;
146    case FT_NORECURSE:
147       Jmsg(jcr, M_SKIPPED, 1, _("     Recursion turned off. Directory skipped: %s\n"), ff_pkt->fname);
148       return 1;
149    case FT_NOFSCHG:
150       Jmsg(jcr, M_SKIPPED, 1, _("     File system change prohibited. Directory skipped: %s\n"), ff_pkt->fname);
151       return 1;
152    case FT_NOOPEN: {
153       berrno be;
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());
156       jcr->Errors++;
157       return 1;
158    }
159    default:
160       Jmsg(jcr, M_NOTSAVED, 0, _("     Unknown file type %d: %s\n"), ff_pkt->type, ff_pkt->fname);
161       jcr->Errors++;
162       return 1;
163    }
164
165    /* Encode attributes and possibly extend them */
166    encode_stat(attribs, ff_pkt, 0);
167    encode_attribsEx(jcr, attribsEx, ff_pkt);
168
169    jcr->lock();
170    jcr->JobFiles++;                  /* increment number of files sent */
171    pm_strcpy(jcr->last_fname, ff_pkt->fname);
172    jcr->unlock();
173
174    /*
175     * Send file attributes to Director
176     *   File_index
177     *   Stream
178     *   Verify Options
179     *   Filename (full path)
180     *   Encoded attributes
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.
184     */
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,
195                0, attribs, 0, 0);
196    } else {
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,
199             0, attribs, 0, 0);
200    }
201    Dmsg2(20, "bfiled>bdird: attribs len=%d: msg=%s\n", dir->msglen, dir->msg);
202    if (!stat) {
203       Jmsg(jcr, M_FATAL, 0, _("Network error in send to Director: ERR=%s\n"), bnet_strerror(dir));
204       return 0;
205    }
206
207    /*
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.
210     */
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))) {
213       /*
214        * Create our digest context. If this fails, the digest will be set to NULL
215        * and not used.
216        */
217       if (ff_pkt->flags & FO_MD5) {
218          digest = crypto_digest_new(CRYPTO_DIGEST_MD5);
219          digest_stream = STREAM_MD5_DIGEST;
220
221       } else if (ff_pkt->flags & FO_SHA1) {
222          digest = crypto_digest_new(CRYPTO_DIGEST_SHA1);
223          digest_stream = STREAM_SHA1_DIGEST;
224
225       } else if (ff_pkt->flags & FO_SHA256) {
226          digest = crypto_digest_new(CRYPTO_DIGEST_SHA256);
227          digest_stream = STREAM_SHA256_DIGEST;
228
229       } else if (ff_pkt->flags & FO_SHA512) {
230          digest = crypto_digest_new(CRYPTO_DIGEST_SHA512);
231          digest_stream = STREAM_SHA512_DIGEST;
232       }
233
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));
238       }
239
240       /* compute MD5 or SHA1 hash */
241       if (digest) {
242          char md[CRYPTO_DIGEST_MAX_SIZE];
243          uint32_t size;
244
245          size = sizeof(md);
246          
247          if (digest_file(jcr, ff_pkt, digest) != 0) {
248             jcr->Errors++;
249             return 1;
250          }
251
252          if (crypto_digest_finalize(digest, (uint8_t *)md, &size)) {
253             char *digest_buf;
254             const char *digest_name;
255             
256             digest_buf = (char *)malloc(BASE64_SIZE(size));
257             digest_name = crypto_digest_name(digest);
258
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);
265
266             free(digest_buf);
267          }
268
269          crypto_digest_free(digest);
270       }
271    }
272
273    return 1;
274 }
275
276 /*
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.
279  */
280 int digest_file(JCR *jcr, FF_PKT *ff_pkt, DIGEST *digest)
281 {
282    BFILE bfd;
283
284    binit(&bfd);
285
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;
291          berrno be;
292          be.set_errno(bfd.berrno);
293          Jmsg(jcr, M_NOTSAVED, 1, _("     Cannot open %s: ERR=%s.\n"),
294                ff_pkt->fname, be.strerror());
295          return 1;
296       }
297       read_digest(&bfd, digest, jcr);
298       bclose(&bfd);
299    }
300
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;
306          berrno be;
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);
311          }
312          return 1;
313       }
314       read_digest(&bfd, digest, jcr);
315       bclose(&bfd);
316    }
317
318    if (digest && ff_pkt->flags & FO_HFSPLUS) {
319       crypto_digest_update(digest, (uint8_t *)ff_pkt->hfsinfo.fndrinfo, 32);
320    }
321 #endif
322
323    return 0;
324 }
325
326 /*
327  * Read message digest of bfd, updating digest
328  * In case of errors we need the job control record and file name.
329  */
330 int read_digest(BFILE *bfd, DIGEST *digest, JCR *jcr)
331 {
332    char buf[DEFAULT_NETWORK_BUFFER_SIZE];
333    int64_t n;
334
335    while ((n=bread(bfd, buf, sizeof(buf))) > 0) {
336       crypto_digest_update(digest, (uint8_t *)buf, n);
337       jcr->JobBytes += n;
338       jcr->ReadBytes += n;
339    }
340    if (n < 0) {
341       berrno be;
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());
345       jcr->Errors++;
346       return -1;
347    }
348    return 0;
349 }