]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/filed/restore.c
- Add support for testing the availability of a PEM-encoded private key
[bacula/bacula] / bacula / src / filed / restore.c
1 /*
2  *  Bacula File Daemon  restore.c Restorefiles.
3  *
4  *    Kern Sibbald, November MM
5  *
6  *   Version $Id$
7  *
8  */
9 /*
10    Copyright (C) 2000-2005 Kern Sibbald
11
12    This program is free software; you can redistribute it and/or
13    modify it under the terms of the GNU General Public License
14    version 2 as amended with additional clauses defined in the
15    file LICENSE in the main source directory.
16
17    This program is distributed in the hope that it will be useful,
18    but WITHOUT ANY WARRANTY; without even the implied warranty of
19    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 
20    the file LICENSE for additional details.
21
22  */
23
24 #include "bacula.h"
25 #include "filed.h"
26
27 #ifdef HAVE_DARWIN_OS
28 #include <sys/attr.h>
29 #endif
30
31 /* Data received from Storage Daemon */
32 static char rec_header[] = "rechdr %ld %ld %ld %ld %ld";
33
34 /* Forward referenced functions */
35 #ifdef HAVE_LIBZ
36 static const char *zlib_strerror(int stat);
37 #endif
38
39 int verify_signature(JCR *jcr, SIGNATURE *sig);
40 int32_t extract_data(JCR *jcr, BFILE *bfd, POOLMEM *buf, int32_t buflen,
41       uint64_t *addr, int flags);
42
43 #define RETRY 10                      /* retry wait time */
44
45 /*
46  * Close a bfd check that we are at the expected file offset.
47  * Makes some code in set_attributes().
48  */
49 int bclose_chksize(JCR *jcr, BFILE *bfd, off_t osize)
50 {
51    char ec1[50], ec2[50];
52    off_t fsize;
53
54    fsize = blseek(bfd, 0, SEEK_CUR);
55    bclose(bfd);                              /* first close file */
56    if (fsize > 0 && fsize != osize) {
57       Qmsg3(jcr, M_ERROR, 0, _("Size of data or stream of %s not correct. Original %s, restored %s.\n"),
58             jcr->last_fname, edit_uint64(osize, ec1),
59             edit_uint64(fsize, ec2));
60       return -1;
61    }
62    return 0;
63 }
64
65 /*
66  * Restore the requested files.
67  *
68  */
69 void do_restore(JCR *jcr)
70 {
71    BSOCK *sd;
72    int32_t stream = 0;
73    int32_t prev_stream;
74    uint32_t VolSessionId, VolSessionTime;
75    bool extract = false;
76    int32_t file_index;
77    char ec1[50];                      /* Buffer printing huge values */
78
79    BFILE bfd;                         /* File content */
80    uint64_t fileAddr = 0;             /* file write address */
81    uint32_t size;                     /* Size of file */
82    BFILE altbfd;                      /* Alternative data stream */
83    uint64_t alt_addr = 0;             /* Write address for alternative stream */
84    intmax_t alt_size = 0;             /* Size of alternate stream */
85    SIGNATURE *sig = NULL;             /* Cryptographic signature (if any) for file */
86    CRYPTO_SESSION *cs = NULL;         /* Cryptographic session data (if any) for file */
87    int flags;                         /* Options for extract_data() */
88    int stat;
89    ATTR *attr;
90
91    /* The following variables keep track of "known unknowns" */
92    int non_support_data = 0;
93    int non_support_attr = 0;
94    int non_support_rsrc = 0;
95    int non_support_finfo = 0;
96    int non_support_acl = 0;
97    int non_support_progname = 0;
98
99    /* Finally, set up for special configurations */
100 #ifdef HAVE_DARWIN_OS
101    intmax_t rsrc_len = 0;             /* Original length of resource fork */
102    struct attrlist attrList;
103
104    memset(&attrList, 0, sizeof(attrList));
105    attrList.bitmapcount = ATTR_BIT_MAP_COUNT;
106    attrList.commonattr = ATTR_CMN_FNDRINFO;
107 #endif
108
109    sd = jcr->store_bsock;
110    set_jcr_job_status(jcr, JS_Running);
111
112    LockRes();
113    CLIENT *client = (CLIENT *)GetNextRes(R_CLIENT, NULL);
114    UnlockRes();
115    uint32_t buf_size;
116    if (client) {
117       buf_size = client->max_network_buffer_size;
118    } else {
119       buf_size = 0;                   /* use default */
120    }
121    if (!bnet_set_buffer_size(sd, buf_size, BNET_SETBUF_WRITE)) {
122       set_jcr_job_status(jcr, JS_ErrorTerminated);
123       return;
124    }
125    jcr->buf_size = sd->msglen;
126
127 #ifdef HAVE_LIBZ
128    uint32_t compress_buf_size = jcr->buf_size + 12 + ((jcr->buf_size+999) / 1000) + 100;
129    jcr->compress_buf = (char *)bmalloc(compress_buf_size);
130    jcr->compress_buf_size = compress_buf_size;
131 #endif
132
133    /*
134     * Get a record from the Storage daemon. We are guaranteed to
135     *   receive records in the following order:
136     *   1. Stream record header
137     *   2. Stream data
138     *        a. Attributes (Unix or Win32)
139     *        b. Possibly stream encryption session data (e.g., symmetric session key)
140     *    or  c. File data for the file
141     *    or  d. Alternate data stream (e.g. Resource Fork)
142     *    or  e. Finder info
143     *    or  f. ACLs
144     *    or  g. Possibly a cryptographic signature
145     *    or  h. Possibly MD5 or SHA1 record
146     *   3. Repeat step 1
147     *
148     * NOTE: We keep track of two bacula file descriptors:
149     *   1. bfd for file data.
150     *      This fd is opened for non empty files when an attribute stream is
151     *      encountered and closed when we find the next attribute stream.
152     *   2. alt_bfd for alternate data streams
153     *      This fd is opened every time we encounter a new alternate data
154     *      stream for the current file. When we find any other stream, we
155     *      close it again.
156     *      The expected size of the stream, alt_len, should be set when
157     *      opening the fd.
158     */
159    binit(&bfd);
160    binit(&altbfd);
161    attr = new_attr();
162    jcr->acl_text = get_pool_memory(PM_MESSAGE);
163
164    while (bget_msg(sd) >= 0 && !job_canceled(jcr)) {
165       /* Remember previous stream type */
166       prev_stream = stream;
167
168       /* First we expect a Stream Record Header */
169       if (sscanf(sd->msg, rec_header, &VolSessionId, &VolSessionTime, &file_index,
170           &stream, &size) != 5) {
171          Jmsg1(jcr, M_FATAL, 0, _("Record header scan error: %s\n"), sd->msg);
172          goto bail_out;
173       }
174       Dmsg2(30, "Got hdr: FilInx=%d Stream=%d.\n", file_index, stream);
175
176       /* * Now we expect the Stream Data */
177       if (bget_msg(sd) < 0) {
178          Jmsg1(jcr, M_FATAL, 0, _("Data record error. ERR=%s\n"), bnet_strerror(sd));
179          goto bail_out;
180       }
181       if (size != (uint32_t)sd->msglen) {
182          Jmsg2(jcr, M_FATAL, 0, _("Actual data size %d not same as header %d\n"), sd->msglen, size);
183          goto bail_out;
184       }
185       Dmsg1(30, "Got stream data, len=%d\n", sd->msglen);
186
187       /* If we change streams, close and reset alternate data streams */
188       if (prev_stream != stream) {
189          if (is_bopen(&altbfd)) {
190             bclose_chksize(jcr, &altbfd, alt_size);
191          }
192          alt_size = -1; /* Use an impossible value and set a proper one below */
193          alt_addr = 0;
194       }
195
196       /* File Attributes stream */
197       switch (stream) {
198       case STREAM_UNIX_ATTRIBUTES:
199       case STREAM_UNIX_ATTRIBUTES_EX:
200          Dmsg1(30, "Stream=Unix Attributes. extract=%d\n", extract);
201          /*
202           * If extracting, it was from previous stream, so
203           * close the output file and validate the signature.
204           */
205          if (extract) {
206             if (size > 0 && !is_bopen(&bfd)) {
207                Jmsg0(jcr, M_ERROR, 0, _("Logic error: output file should be open\n"));
208             }
209             set_attributes(jcr, attr, &bfd);
210             extract = false;
211
212             /* Verify the cryptographic signature, if any */
213             if (jcr->pki_sign) {
214                if (sig) {
215                   if (!verify_signature(jcr, sig)) {
216                      // TODO landonf: Better signature failure handling.
217                      // The failure is reported to the director in verify_signature() ...
218                      Dmsg1(100, "Bad signature on %s\n", jcr->last_fname);
219                   } else {
220                      Dmsg1(100, "Signature good on %s\n", jcr->last_fname);
221                   }
222                } else {
223                   Jmsg1(jcr, M_ERROR, 0, _("Missing cryptographic signature for %s\n"), jcr->last_fname);
224                }
225             }
226
227             /* Free Signature */
228             if (sig) {
229                crypto_sign_free(sig);
230                sig = NULL;
231             }
232
233             if (cs) {
234                crypto_session_free(cs);
235                cs = NULL;
236             }
237
238             Dmsg0(30, "Stop extracting.\n");
239          } else if (is_bopen(&bfd)) {
240             Jmsg0(jcr, M_ERROR, 0, _("Logic error: output file should not be open\n"));
241             bclose(&bfd);
242          }
243
244          /*
245           * Unpack and do sanity check fo attributes.
246           */
247          if (!unpack_attributes_record(jcr, stream, sd->msg, attr)) {
248             goto bail_out;
249          }
250          if (file_index != attr->file_index) {
251             Jmsg(jcr, M_FATAL, 0, _("Record header file index %ld not equal record index %ld\n"),
252                  file_index, attr->file_index);
253             Dmsg0(100, "File index error\n");
254             goto bail_out;
255          }
256
257          Dmsg3(200, "File %s\nattrib=%s\nattribsEx=%s\n", attr->fname,
258                attr->attr, attr->attrEx);
259
260          attr->data_stream = decode_stat(attr->attr, &attr->statp, &attr->LinkFI);
261
262          if (!is_restore_stream_supported(attr->data_stream)) {
263             if (!non_support_data++) {
264                Jmsg(jcr, M_ERROR, 0, _("%s stream not supported on this Client.\n"),
265                   stream_to_ascii(attr->data_stream));
266             }
267             continue;
268          }
269
270          build_attr_output_fnames(jcr, attr);
271
272          /*
273           * Now determine if we are extracting or not.
274           */
275          jcr->num_files_examined++;
276          Dmsg1(30, "Outfile=%s\n", attr->ofname);
277          extract = false;
278          stat = create_file(jcr, attr, &bfd, jcr->replace);
279          switch (stat) {
280          case CF_ERROR:
281          case CF_SKIP:
282             break;
283          case CF_EXTRACT:        /* File created and we expect file data */
284             extract = true;
285             /* FALLTHROUGH */
286          case CF_CREATED:        /* File created, but there is no content */
287             P(jcr->mutex);
288             pm_strcpy(jcr->last_fname, attr->ofname);
289             V(jcr->mutex);
290             jcr->JobFiles++;
291             fileAddr = 0;
292             print_ls_output(jcr, attr);
293 #ifdef HAVE_DARWIN_OS
294             /* Only restore the resource fork for regular files */
295             from_base64(&rsrc_len, attr->attrEx);
296             if (attr->type == FT_REG && rsrc_len > 0) {
297                extract = true;
298             }
299 #endif
300             if (!extract) {
301                /* set attributes now because file will not be extracted */
302                set_attributes(jcr, attr, &bfd);
303             }
304             break;
305          }
306          break;
307
308       /* Data stream */
309       case STREAM_ENCRYPTED_SESSION_DATA:
310          Dmsg1(30, "Stream=Encrypted Session Data, size: %d\n", sd->msglen);
311          /* Save session keys . */
312          switch(crypto_session_decode(sd->msg, (size_t) sd->msglen, jcr->pki_recipients, &cs)) {
313          case CRYPTO_ERROR_NONE:
314             /* Success */
315             break;
316          case CRYPTO_ERROR_NORECIPIENT:
317             Jmsg(jcr, M_ERROR, 0, _("Missing private key required to decrypt encrypted backup data."));
318             break;
319          case CRYPTO_ERROR_DECRYPTION:
320             Jmsg(jcr, M_ERROR, 0, _("Decrypt of the session key failed."));
321             break;
322          default:
323             /* Shouldn't happen */
324             Jmsg(jcr, M_ERROR, 0, _("An error occured while decoding encrypted session data stream."));
325             break;
326          }
327
328          break;
329
330       case STREAM_FILE_DATA:
331       case STREAM_SPARSE_DATA:
332       case STREAM_WIN32_DATA:
333       case STREAM_GZIP_DATA:
334       case STREAM_SPARSE_GZIP_DATA:
335       case STREAM_WIN32_GZIP_DATA:
336          /* Force an expected, consistent stream type here */
337          if (extract && (prev_stream == stream || prev_stream == STREAM_UNIX_ATTRIBUTES
338                   || prev_stream == STREAM_UNIX_ATTRIBUTES_EX
339                   || prev_stream == STREAM_ENCRYPTED_SESSION_DATA)) {
340             flags = 0;
341             if (stream == STREAM_SPARSE_DATA || stream == STREAM_SPARSE_GZIP_DATA) {
342                flags |= FO_SPARSE;
343             }
344             if (stream == STREAM_GZIP_DATA || stream == STREAM_SPARSE_GZIP_DATA
345                   || stream == STREAM_WIN32_GZIP_DATA) {
346                flags |= FO_GZIP;
347             }
348
349             if (is_win32_stream(stream) && !have_win32_api()) {
350                set_portable_backup(&bfd);
351                flags |= FO_WIN32DECOMP;    /* "decompose" BackupWrite data */
352             }
353
354             if (extract_data(jcr, &bfd, sd->msg, sd->msglen, &fileAddr, flags) < 0) {
355                extract = false;
356                bclose(&bfd);
357                continue;
358             }
359          }
360          break;
361
362       /* Resource fork stream - only recorded after a file to be restored */
363       /* Silently ignore if we cannot write - we already reported that */
364       case STREAM_MACOS_FORK_DATA:
365 #ifdef HAVE_DARWIN_OS
366          if (extract) {
367             if (prev_stream != stream) {
368                if (bopen_rsrc(&altbfd, jcr->last_fname, O_WRONLY | O_TRUNC | O_BINARY, 0) < 0) {
369                   Jmsg(jcr, M_ERROR, 0, _("     Cannot open resource fork for %s.\n"), jcr->last_fname);
370                   extract = false;
371                   continue;
372                }
373                alt_size = rsrc_len;
374                Dmsg0(30, "Restoring resource fork\n");
375             }
376             flags = 0;
377             if (extract_data(jcr, &altbfd, sd->msg, sd->msglen, &alt_addr, flags) < 0) {
378                extract = false;
379                bclose(&altbfd);
380                continue;
381             }
382          }
383 #else
384          non_support_rsrc++;
385 #endif
386          break;
387
388       case STREAM_HFSPLUS_ATTRIBUTES:
389 #ifdef HAVE_DARWIN_OS
390          Dmsg0(30, "Restoring Finder Info\n");
391          if (sd->msglen != 32) {
392             Jmsg(jcr, M_ERROR, 0, _("     Invalid length of Finder Info (got %d, not 32)\n"), sd->msglen);
393             continue;
394          }
395          if (setattrlist(jcr->last_fname, &attrList, sd->msg, sd->msglen, 0) != 0) {
396             Jmsg(jcr, M_ERROR, 0, _("     Could not set Finder Info on %s\n"), jcr->last_fname);
397             continue;
398          }
399 #else
400          non_support_finfo++;
401 #endif
402
403       case STREAM_UNIX_ATTRIBUTES_ACCESS_ACL:
404 #ifdef HAVE_ACL
405          pm_strcpy(jcr->acl_text, sd->msg);
406          Dmsg2(400, "Restoring ACL type 0x%2x <%s>\n", BACL_TYPE_ACCESS, jcr->acl_text);
407          if (bacl_set(jcr, BACL_TYPE_ACCESS) != 0) {
408                Qmsg1(jcr, M_WARNING, 0, _("Can't restore ACL of %s\n"), jcr->last_fname);
409          }
410 #else 
411          non_support_acl++;
412 #endif
413          break;
414
415       case STREAM_UNIX_ATTRIBUTES_DEFAULT_ACL:
416 #ifdef HAVE_ACL
417          pm_strcpy(jcr->acl_text, sd->msg);
418          Dmsg2(400, "Restoring ACL type 0x%2x <%s>\n", BACL_TYPE_DEFAULT, jcr->acl_text);
419          if (bacl_set(jcr, BACL_TYPE_DEFAULT) != 0) {
420                Qmsg1(jcr, M_WARNING, 0, _("Can't restore default ACL of %s\n"), jcr->last_fname);
421          }
422 #else 
423          non_support_acl++;
424 #endif
425          break;
426
427       case STREAM_SIGNED_DIGEST:
428          /* Save signature. */
429          sig = crypto_sign_decode(sd->msg, (size_t) sd->msglen);
430          break;
431
432       case STREAM_MD5_DIGEST:
433       case STREAM_SHA1_DIGEST:
434       case STREAM_SHA256_DIGEST:
435       case STREAM_SHA512_DIGEST:
436          break;
437
438       case STREAM_PROGRAM_NAMES:
439       case STREAM_PROGRAM_DATA:
440          if (!non_support_progname) {
441             Pmsg0(000, "Got Program Name or Data Stream. Ignored.\n");
442             non_support_progname++;
443          }
444          break;
445
446       default:
447          /* If extracting, wierd stream (not 1 or 2), close output file anyway */
448          if (extract) {
449             Dmsg1(30, "Found wierd stream %d\n", stream);
450             if (size > 0 && !is_bopen(&bfd)) {
451                Jmsg0(jcr, M_ERROR, 0, _("Logic error: output file should be open\n"));
452             }
453             set_attributes(jcr, attr, &bfd);
454             extract = false;
455          } else if (is_bopen(&bfd)) {
456             Jmsg0(jcr, M_ERROR, 0, _("Logic error: output file should not be open\n"));
457             bclose(&bfd);
458          }
459          Jmsg(jcr, M_ERROR, 0, _("Unknown stream=%d ignored. This shouldn't happen!\n"), stream);
460          Dmsg2(0, "None of above!!! stream=%d data=%s\n", stream,sd->msg);
461          break;
462       } /* end switch(stream) */
463
464    } /* end while get_msg() */
465
466    /* If output file is still open, it was the last one in the
467     * archive since we just hit an end of file, so close the file.
468     */
469    if (is_bopen(&altbfd)) {
470       bclose_chksize(jcr, &altbfd, alt_size);
471    }
472    if (extract) {
473       set_attributes(jcr, attr, &bfd);
474    }
475    if (is_bopen(&bfd)) {
476       bclose(&bfd);
477    }
478    set_jcr_job_status(jcr, JS_Terminated);
479    goto ok_out;
480
481 bail_out:
482    set_jcr_job_status(jcr, JS_ErrorTerminated);
483 ok_out:
484    if (jcr->compress_buf) {
485       free(jcr->compress_buf);
486       jcr->compress_buf = NULL;
487       jcr->compress_buf_size = 0;
488    }
489    bclose(&altbfd);
490    bclose(&bfd);
491    free_attr(attr);
492    free_pool_memory(jcr->acl_text);
493    Dmsg2(10, "End Do Restore. Files=%d Bytes=%s\n", jcr->JobFiles,
494       edit_uint64(jcr->JobBytes, ec1));
495    if (non_support_data > 1 || non_support_attr > 1) {
496       Jmsg(jcr, M_ERROR, 0, _("%d non-supported data streams and %d non-supported attrib streams ignored.\n"),
497          non_support_data, non_support_attr);
498    }
499    if (non_support_rsrc) {
500       Jmsg(jcr, M_INFO, 0, _("%d non-supported resource fork streams ignored.\n"), non_support_rsrc);
501    }
502    if (non_support_finfo) {
503       Jmsg(jcr, M_INFO, 0, _("%d non-supported Finder Info streams ignored.\n"), non_support_rsrc);
504    }
505    if (non_support_acl) {
506       Jmsg(jcr, M_INFO, 0, _("%d non-supported acl streams ignored.\n"), non_support_acl);
507    }
508
509 }
510
511 #ifdef HAVE_LIBZ
512 /*
513  * Convert ZLIB error code into an ASCII message
514  */
515 static const char *zlib_strerror(int stat)
516 {
517    if (stat >= 0) {
518       return _("None");
519    }
520    switch (stat) {
521    case Z_ERRNO:
522       return _("Zlib errno");
523    case Z_STREAM_ERROR:
524       return _("Zlib stream error");
525    case Z_DATA_ERROR:
526       return _("Zlib data error");
527    case Z_MEM_ERROR:
528       return _("Zlib memory error");
529    case Z_BUF_ERROR:
530       return _("Zlib buffer error");
531    case Z_VERSION_ERROR:
532       return _("Zlib version error");
533    default:
534       return _("*none*");
535    }
536 }
537 #endif
538
539 static int do_file_digest(FF_PKT *ff_pkt, void *pkt, bool top_level) {
540    JCR *jcr = (JCR *) pkt;
541    return (digest_file(jcr, ff_pkt, jcr->digest));
542 }
543
544 /*
545  * Verify the signature for the last restored file
546  * Return value is either true (signature correct)
547  * or false (signature could not be verified).
548  */
549 int verify_signature(JCR *jcr, SIGNATURE *sig)
550 {
551    X509_KEYPAIR *keypair;
552    DIGEST *digest = NULL;
553    crypto_error_t err;
554
555
556    /* Iterate through the trusted signers */
557    foreach_alist(keypair, jcr->pki_signers) {
558       err = crypto_sign_get_digest(sig, jcr->pki_keypair, &digest);
559
560       switch (err) {
561       case CRYPTO_ERROR_NONE:
562          /* Signature found, digest allocated */
563          jcr->digest = digest;
564
565          /* Checksum the entire file */
566          if (find_one_file(jcr, jcr->ff, do_file_digest, jcr, jcr->last_fname, (dev_t)-1, 1) != 0) {
567             Qmsg(jcr, M_ERROR, 0, _("Signature validation failed for %s: \n"), jcr->last_fname);
568             return false;
569          }
570
571          /* Verify the signature */
572          if ((err = crypto_sign_verify(sig, keypair, digest)) != CRYPTO_ERROR_NONE) {
573             Qmsg2(jcr, M_ERROR, 0, _("Signature validation failed for %s: %s\n"), jcr->last_fname, crypto_strerror(err));
574             crypto_digest_free(digest);
575             return false;
576          }
577
578          /* Valid signature */
579          crypto_digest_free(digest);
580          return true;
581
582       case CRYPTO_ERROR_NOSIGNER:
583          /* Signature not found, try again */
584          continue;
585       default:
586          /* Something strange happened (that shouldn't happen!)... */
587          Qmsg2(jcr, M_ERROR, 0, _("Signature validation failed for %s: %s\n"), jcr->last_fname, crypto_strerror(err));
588          if (digest) {
589             crypto_digest_free(digest);
590          }
591          return false;
592       }
593    }
594
595    /* Unreachable */
596    return false;
597 }
598
599 /*
600  * In the context of jcr, write data to bfd.
601  * We write buflen bytes in buf at addr. addr is updated in place.
602  * The flags specify whether to use sparse files or compression.
603  * Return value is the number of bytes written, or -1 on errors.
604  */
605 int32_t extract_data(JCR *jcr, BFILE *bfd, POOLMEM *buf, int32_t buflen,
606       uint64_t *addr, int flags)
607 {
608    int stat;
609    char *wbuf;                        /* write buffer */
610    uint32_t wsize;                    /* write size */
611    uint32_t rsize;                    /* read size */
612    char ec1[50];                      /* Buffer printing huge values */
613
614    if (flags & FO_SPARSE) {
615       ser_declare;
616       uint64_t faddr;
617       char ec1[50];
618       wbuf = buf + SPARSE_FADDR_SIZE;
619       rsize = buflen - SPARSE_FADDR_SIZE;
620       ser_begin(buf, SPARSE_FADDR_SIZE);
621       unser_uint64(faddr);
622       if (*addr != faddr) {
623          *addr = faddr;
624          if (blseek(bfd, (off_t)*addr, SEEK_SET) < 0) {
625             berrno be;
626             Jmsg3(jcr, M_ERROR, 0, _("Seek to %s error on %s: ERR=%s\n"),
627                   edit_uint64(*addr, ec1), jcr->last_fname, 
628                   be.strerror(bfd->berrno));
629             return -1;
630          }
631       }
632    } else {
633       wbuf = buf;
634       rsize = buflen;
635    }
636    wsize = rsize;
637
638    if (flags & FO_GZIP) {
639 #ifdef HAVE_LIBZ
640       uLong compress_len;
641       /* 
642        * NOTE! We only use uLong and Byte because they are
643        *  needed by the zlib routines, they should not otherwise
644        *  be used in Bacula.
645        */
646       compress_len = jcr->compress_buf_size;
647       Dmsg2(100, "Comp_len=%d msglen=%d\n", compress_len, wsize);
648       if ((stat=uncompress((Byte *)jcr->compress_buf, &compress_len,
649                   (const Byte *)wbuf, (uLong)rsize)) != Z_OK) {
650          Qmsg(jcr, M_ERROR, 0, _("Uncompression error on file %s. ERR=%s\n"),
651                jcr->last_fname, zlib_strerror(stat));
652          return -1;
653       }
654       wbuf = jcr->compress_buf;
655       wsize = compress_len;
656       Dmsg2(100, "Write uncompressed %d bytes, total before write=%s\n", compress_len, edit_uint64(jcr->JobBytes, ec1));
657 #else
658       Qmsg(jcr, M_ERROR, 0, _("GZIP data stream found, but GZIP not configured!\n"));
659       return -1;
660 #endif
661    } else {
662       Dmsg2(30, "Write %u bytes, total before write=%s\n", wsize, edit_uint64(jcr->JobBytes, ec1));
663    }
664
665    if (flags & FO_WIN32DECOMP) {
666       if (!processWin32BackupAPIBlock(bfd, wbuf, wsize)) {
667          berrno be;
668          Jmsg2(jcr, M_ERROR, 0, _("Write error in Win32 Block Decomposition on %s: %s\n"), 
669                jcr->last_fname, be.strerror(bfd->berrno));
670          return -1;
671       }
672    } else if (bwrite(bfd, wbuf, wsize) != (ssize_t)wsize) {
673       berrno be;
674       Jmsg2(jcr, M_ERROR, 0, _("Write error on %s: %s\n"), 
675             jcr->last_fname, be.strerror(bfd->berrno));
676       return -1;
677    }
678
679    jcr->JobBytes += wsize;
680    jcr->ReadBytes += rsize;
681    *addr += wsize;
682
683    return wsize;
684 }