]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/filed/verify.c
Make out of freespace non-fatal for removable devices -- i.e. behaves like tape
[bacula/bacula] / bacula / src / filed / verify.c
1 /*
2    Bacula(R) - The Network Backup Solution
3
4    Copyright (C) 2000-2015 Kern Sibbald
5
6    The original author of Bacula is Kern Sibbald, with contributions
7    from many others, a complete list can be found in the file AUTHORS.
8
9    You may use this file and others of this release according to the
10    license defined in the LICENSE file, which includes the Affero General
11    Public License, v3.0 ("AGPLv3") and some additional permissions and
12    terms pursuant to its AGPLv3 Section 7.
13
14    This notice must be preserved when any source code is 
15    conveyed and/or propagated.
16
17    Bacula(R) is a registered trademark of Kern Sibbald.
18 */
19 /*
20  *  Bacula File Daemon  verify.c  Verify files.
21  *
22  *    Kern Sibbald, October MM
23  *
24  */
25
26 #include "bacula.h"
27 #include "filed.h"
28
29 static int verify_file(JCR *jcr, FF_PKT *ff_pkt, bool);
30 static int read_digest(BFILE *bfd, DIGEST *digest, JCR *jcr);
31
32 /*
33  * Find all the requested files and send attributes
34  * to the Director.
35  *
36  */
37 void do_verify(JCR *jcr)
38 {
39    jcr->setJobStatus(JS_Running);
40    jcr->buf_size = DEFAULT_NETWORK_BUFFER_SIZE;
41    if ((jcr->big_buf = (char *) malloc(jcr->buf_size)) == NULL) {
42       Jmsg1(jcr, M_ABORT, 0, _("Cannot malloc %d network read buffer\n"),
43          DEFAULT_NETWORK_BUFFER_SIZE);
44    }
45    set_find_options((FF_PKT *)jcr->ff, jcr->incremental, jcr->mtime);
46    Dmsg0(10, "Start find files\n");
47    /* Subroutine verify_file() is called for each file */
48    find_files(jcr, (FF_PKT *)jcr->ff, verify_file, NULL);
49    Dmsg0(10, "End find files\n");
50
51    if (jcr->big_buf) {
52       free(jcr->big_buf);
53       jcr->big_buf = NULL;
54    }
55    jcr->setJobStatus(JS_Terminated);
56 }
57
58 /*
59  * Called here by find() for each file.
60  *
61  *  Find the file, compute the MD5 or SHA1 and send it back to the Director
62  */
63 static int verify_file(JCR *jcr, FF_PKT *ff_pkt, bool top_level)
64 {
65    char attribs[MAXSTRING];
66    char attribsEx[MAXSTRING];
67    int digest_stream = STREAM_NONE;
68    int stat;
69    DIGEST *digest = NULL;
70    BSOCK *dir;
71
72    if (job_canceled(jcr)) {
73       return 0;
74    }
75
76    dir = jcr->dir_bsock;
77    jcr->num_files_examined++;         /* bump total file count */
78
79    switch (ff_pkt->type) {
80    case FT_LNKSAVED:                  /* Hard linked, file already saved */
81       Dmsg2(30, "FT_LNKSAVED saving: %s => %s\n", ff_pkt->fname, ff_pkt->link);
82       break;
83    case FT_REGE:
84       Dmsg1(30, "FT_REGE saving: %s\n", ff_pkt->fname);
85       break;
86    case FT_REG:
87       Dmsg1(30, "FT_REG saving: %s\n", ff_pkt->fname);
88       break;
89    case FT_LNK:
90       Dmsg2(30, "FT_LNK saving: %s -> %s\n", ff_pkt->fname, ff_pkt->link);
91       break;
92    case FT_DIRBEGIN:
93       jcr->num_files_examined--;      /* correct file count */
94       return 1;                       /* ignored */
95    case FT_REPARSE:
96    case FT_JUNCTION:
97    case FT_DIREND:
98       Dmsg1(30, "FT_DIR saving: %s\n", ff_pkt->fname);
99       break;
100    case FT_SPEC:
101       Dmsg1(30, "FT_SPEC saving: %s\n", ff_pkt->fname);
102       break;
103    case FT_RAW:
104       Dmsg1(30, "FT_RAW saving: %s\n", ff_pkt->fname);
105       break;
106    case FT_FIFO:
107       Dmsg1(30, "FT_FIFO saving: %s\n", ff_pkt->fname);
108       break;
109    case FT_NOACCESS: {
110       berrno be;
111       be.set_errno(ff_pkt->ff_errno);
112       Jmsg(jcr, M_NOTSAVED, 1, _("     Could not access %s: ERR=%s\n"), ff_pkt->fname, be.bstrerror());
113       jcr->JobErrors++;
114       return 1;
115    }
116    case FT_NOFOLLOW: {
117       berrno be;
118       be.set_errno(ff_pkt->ff_errno);
119       Jmsg(jcr, M_NOTSAVED, 1, _("     Could not follow link %s: ERR=%s\n"), ff_pkt->fname, be.bstrerror());
120       jcr->JobErrors++;
121       return 1;
122    }
123    case FT_NOSTAT: {
124       berrno be;
125       be.set_errno(ff_pkt->ff_errno);
126       Jmsg(jcr, M_NOTSAVED, 1, _("     Could not stat %s: ERR=%s\n"), ff_pkt->fname, be.bstrerror());
127       jcr->JobErrors++;
128       return 1;
129    }
130    case FT_DIRNOCHG:
131    case FT_NOCHG:
132       Jmsg(jcr, M_SKIPPED, 1, _("     Unchanged file skipped: %s\n"), ff_pkt->fname);
133       return 1;
134    case FT_ISARCH:
135       Jmsg(jcr, M_SKIPPED, 1, _("     Archive file skipped: %s\n"), ff_pkt->fname);
136       return 1;
137    case FT_NORECURSE:
138       Jmsg(jcr, M_SKIPPED, 1, _("     Recursion turned off. Directory skipped: %s\n"), ff_pkt->fname);
139       ff_pkt->type = FT_DIREND;     /* directory entry was backed up */
140       break;
141    case FT_NOFSCHG:
142       Jmsg(jcr, M_SKIPPED, 1, _("     File system change prohibited. Directory skipped: %s\n"), ff_pkt->fname);
143       return 1;
144    case FT_PLUGIN_CONFIG:
145    case FT_RESTORE_FIRST:
146       return 1;                       /* silently skip */
147    case FT_NOOPEN: {
148       berrno be;
149       be.set_errno(ff_pkt->ff_errno);
150       Jmsg(jcr, M_NOTSAVED, 1, _("     Could not open directory %s: ERR=%s\n"), ff_pkt->fname, be.bstrerror());
151       jcr->JobErrors++;
152       return 1;
153    }
154    default:
155       Jmsg(jcr, M_NOTSAVED, 0, _("     Unknown file type %d: %s\n"), ff_pkt->type, ff_pkt->fname);
156       jcr->JobErrors++;
157       return 1;
158    }
159
160    /* Encode attributes and possibly extend them */
161    encode_stat(attribs, &ff_pkt->statp, sizeof(ff_pkt->statp), ff_pkt->LinkFI, 0);
162    encode_attribsEx(jcr, attribsEx, ff_pkt);
163
164    jcr->lock();
165    jcr->JobFiles++;                  /* increment number of files sent */
166    pm_strcpy(jcr->last_fname, ff_pkt->fname);
167    jcr->unlock();
168
169    /*
170     * Send file attributes to Director
171     *   File_index
172     *   Stream
173     *   Verify Options
174     *   Filename (full path)
175     *   Encoded attributes
176     *   Link name (if type==FT_LNK)
177     * For a directory, link is the same as fname, but with trailing
178     * slash. For a linked file, link is the link.
179     */
180    /* Send file attributes to Director (note different format than for Storage) */
181    Dmsg2(400, "send ATTR inx=%d fname=%s\n", jcr->JobFiles, ff_pkt->fname);
182    if (ff_pkt->type == FT_LNK || ff_pkt->type == FT_LNKSAVED) {
183       stat = dir->fsend("%d %d %s %s%c%s%c%s%c", jcr->JobFiles,
184                         STREAM_UNIX_ATTRIBUTES, ff_pkt->VerifyOpts, ff_pkt->fname,
185                         0, attribs, 0, ff_pkt->link, 0);
186    } else if (ff_pkt->type == FT_DIREND || ff_pkt->type == FT_REPARSE ||
187               ff_pkt->type == FT_JUNCTION) {
188       /* Here link is the canonical filename (i.e. with trailing slash) */
189       stat = dir->fsend("%d %d %s %s%c%s%c%c", jcr->JobFiles,
190                         STREAM_UNIX_ATTRIBUTES, ff_pkt->VerifyOpts, ff_pkt->link,
191                         0, attribs, 0, 0);
192    } else {
193       stat = dir->fsend("%d %d %s %s%c%s%c%c", jcr->JobFiles,
194                         STREAM_UNIX_ATTRIBUTES, ff_pkt->VerifyOpts, ff_pkt->fname,
195                         0, attribs, 0, 0);
196    }
197    Dmsg2(20, "bfiled>bdird: attribs len=%d: msg=%s\n", dir->msglen, dir->msg);
198    if (!stat) {
199       Jmsg(jcr, M_FATAL, 0, _("Network error in send to Director: ERR=%s\n"), dir->bstrerror());
200       return 0;
201    }
202
203    /*
204     * The remainder of the function is all about getting the checksum.
205     * First we initialise, then we read files, other streams and Finder Info.
206     */
207    if (ff_pkt->type != FT_LNKSAVED && (S_ISREG(ff_pkt->statp.st_mode) &&
208             ff_pkt->flags & (FO_MD5|FO_SHA1|FO_SHA256|FO_SHA512))) {
209       /*
210        * Create our digest context. If this fails, the digest will be set to NULL
211        * and not used.
212        */
213       if (ff_pkt->flags & FO_MD5) {
214          digest = crypto_digest_new(jcr, CRYPTO_DIGEST_MD5);
215          digest_stream = STREAM_MD5_DIGEST;
216
217       } else if (ff_pkt->flags & FO_SHA1) {
218          digest = crypto_digest_new(jcr, CRYPTO_DIGEST_SHA1);
219          digest_stream = STREAM_SHA1_DIGEST;
220
221       } else if (ff_pkt->flags & FO_SHA256) {
222          digest = crypto_digest_new(jcr, CRYPTO_DIGEST_SHA256);
223          digest_stream = STREAM_SHA256_DIGEST;
224
225       } else if (ff_pkt->flags & FO_SHA512) {
226          digest = crypto_digest_new(jcr, CRYPTO_DIGEST_SHA512);
227          digest_stream = STREAM_SHA512_DIGEST;
228       }
229
230       /* Did digest initialization fail? */
231       if (digest_stream != STREAM_NONE && digest == NULL) {
232          Jmsg(jcr, M_WARNING, 0, _("%s digest initialization failed\n"),
233               stream_to_ascii(digest_stream));
234       }
235
236       /* compute MD5 or SHA1 hash */
237       if (digest) {
238          char md[CRYPTO_DIGEST_MAX_SIZE];
239          uint32_t size;
240
241          size = sizeof(md);
242
243          if (digest_file(jcr, ff_pkt, digest) != 0) {
244             jcr->JobErrors++;
245             goto good_rtn;
246          }
247
248          if (crypto_digest_finalize(digest, (uint8_t *)md, &size)) {
249             char *digest_buf;
250             const char *digest_name;
251
252             digest_buf = (char *)malloc(BASE64_SIZE(size));
253             digest_name = crypto_digest_name(digest);
254
255             bin_to_base64(digest_buf, BASE64_SIZE(size), md, size, true);
256             Dmsg3(400, "send inx=%d %s=%s\n", jcr->JobFiles, digest_name, digest_buf);
257             dir->fsend("%d %d %s *%s-%d*", jcr->JobFiles, digest_stream, digest_buf,
258                        digest_name, jcr->JobFiles);
259             Dmsg3(20, "bfiled>bdird: %s len=%d: msg=%s\n", digest_name,
260                   dir->msglen, dir->msg);
261
262             free(digest_buf);
263          }
264       }
265    }
266
267 good_rtn:
268    if (digest) {
269       crypto_digest_free(digest);
270    }
271    return 1;
272 }
273
274 /*
275  * Compute message digest for the file specified by ff_pkt.
276  * In case of errors we need the job control record and file name.
277  */
278 int digest_file(JCR *jcr, FF_PKT *ff_pkt, DIGEST *digest)
279 {
280    BFILE bfd;
281
282    Dmsg0(50, "=== digest_file\n");
283    binit(&bfd);
284
285    if (ff_pkt->statp.st_size > 0 || ff_pkt->type == FT_RAW
286          || ff_pkt->type == FT_FIFO) {
287       int noatime = ff_pkt->flags & FO_NOATIME ? O_NOATIME : 0;
288       if ((bopen(&bfd, ff_pkt->fname, O_RDONLY | O_BINARY | noatime, 0)) < 0) {
289          ff_pkt->ff_errno = errno;
290          berrno be;
291          be.set_errno(bfd.berrno);
292          Dmsg2(100, "Cannot open %s: ERR=%s\n", ff_pkt->fname, be.bstrerror());
293          Jmsg(jcr, M_ERROR, 1, _("     Cannot open %s: ERR=%s.\n"),
294                ff_pkt->fname, be.bstrerror());
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_ERROR, -1, _("     Cannot open resource fork for %s: ERR=%s.\n"),
308                ff_pkt->fname, be.bstrerror());
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    if (digest && ff_pkt->flags & FO_HFSPLUS) {
318       crypto_digest_update(digest, (uint8_t *)ff_pkt->hfsinfo.fndrinfo, 32);
319    } 
320 #endif
321    return 0;
322 }
323
324 /*
325  * Read message digest of bfd, updating digest
326  * In case of errors we need the job control record and file name.
327  */
328 static int read_digest(BFILE *bfd, DIGEST *digest, JCR *jcr)
329 {
330    char buf[DEFAULT_NETWORK_BUFFER_SIZE];
331    int64_t n;
332    int64_t bufsiz = (int64_t)sizeof(buf);
333    FF_PKT *ff_pkt = (FF_PKT *)jcr->ff;
334    uint64_t fileAddr = 0;             /* file address */
335
336
337    Dmsg0(50, "=== read_digest\n");
338    while ((n=bread(bfd, buf, bufsiz)) > 0) {
339       /* Check for sparse blocks */
340       if (ff_pkt->flags & FO_SPARSE) {
341          bool allZeros = false;
342          if ((n == bufsiz &&
343               fileAddr+n < (uint64_t)ff_pkt->statp.st_size) ||
344              ((ff_pkt->type == FT_RAW || ff_pkt->type == FT_FIFO) &&
345                (uint64_t)ff_pkt->statp.st_size == 0)) {
346             allZeros = is_buf_zero(buf, bufsiz);
347          }
348          fileAddr += n;               /* update file address */
349          /* Skip any block of all zeros */
350          if (allZeros) {
351             continue;                 /* skip block of zeros */
352          }
353       }
354
355       crypto_digest_update(digest, (uint8_t *)buf, n);
356
357       /* Can be used by BaseJobs or with accurate, update only for Verify
358        * jobs
359        */
360       if (jcr->getJobType() == JT_VERIFY) {
361          jcr->JobBytes += n;
362       }
363       jcr->ReadBytes += n;
364    }
365    if (n < 0) {
366       berrno be;
367       be.set_errno(bfd->berrno);
368       Dmsg2(100, "Error reading file %s: ERR=%s\n", jcr->last_fname, be.bstrerror());
369       Jmsg(jcr, M_ERROR, 1, _("Error reading file %s: ERR=%s\n"),
370             jcr->last_fname, be.bstrerror());
371       jcr->JobErrors++;
372       return -1;
373    }
374    return 0;
375 }