]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/filed/restore.c
Fix a logic error in the restoration code that could cause the signature of the last...
[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                   // Failure is reported in verify_signature() ...
216                   verify_signature(jcr, sig);
217                } else {
218                   Jmsg1(jcr, M_ERROR, 0, _("Missing cryptographic signature for %s\n"), jcr->last_fname);
219                }
220             }
221
222             /* Free Signature */
223             if (sig) {
224                crypto_sign_free(sig);
225                sig = NULL;
226             }
227             if (cs) {
228                crypto_session_free(cs);
229                cs = NULL;
230             }
231             Dmsg0(30, "Stop extracting.\n");
232          } else if (is_bopen(&bfd)) {
233             Jmsg0(jcr, M_ERROR, 0, _("Logic error: output file should not be open\n"));
234             bclose(&bfd);
235          }
236
237          /*
238           * Unpack and do sanity check fo attributes.
239           */
240          if (!unpack_attributes_record(jcr, stream, sd->msg, attr)) {
241             goto bail_out;
242          }
243          if (file_index != attr->file_index) {
244             Jmsg(jcr, M_FATAL, 0, _("Record header file index %ld not equal record index %ld\n"),
245                  file_index, attr->file_index);
246             Dmsg0(100, "File index error\n");
247             goto bail_out;
248          }
249
250          Dmsg3(200, "File %s\nattrib=%s\nattribsEx=%s\n", attr->fname,
251                attr->attr, attr->attrEx);
252
253          attr->data_stream = decode_stat(attr->attr, &attr->statp, &attr->LinkFI);
254
255          if (!is_restore_stream_supported(attr->data_stream)) {
256             if (!non_support_data++) {
257                Jmsg(jcr, M_ERROR, 0, _("%s stream not supported on this Client.\n"),
258                   stream_to_ascii(attr->data_stream));
259             }
260             continue;
261          }
262
263          build_attr_output_fnames(jcr, attr);
264
265          /*
266           * Now determine if we are extracting or not.
267           */
268          jcr->num_files_examined++;
269          Dmsg1(30, "Outfile=%s\n", attr->ofname);
270          extract = false;
271          stat = create_file(jcr, attr, &bfd, jcr->replace);
272          switch (stat) {
273          case CF_ERROR:
274          case CF_SKIP:
275             break;
276          case CF_EXTRACT:        /* File created and we expect file data */
277             extract = true;
278             /* FALLTHROUGH */
279          case CF_CREATED:        /* File created, but there is no content */
280             P(jcr->mutex);
281             pm_strcpy(jcr->last_fname, attr->ofname);
282             V(jcr->mutex);
283             jcr->JobFiles++;
284             fileAddr = 0;
285             print_ls_output(jcr, attr);
286 #ifdef HAVE_DARWIN_OS
287             /* Only restore the resource fork for regular files */
288             from_base64(&rsrc_len, attr->attrEx);
289             if (attr->type == FT_REG && rsrc_len > 0) {
290                extract = true;
291             }
292 #endif
293             if (!extract) {
294                /* set attributes now because file will not be extracted */
295                set_attributes(jcr, attr, &bfd);
296             }
297             break;
298          }
299          break;
300
301       /* Data stream */
302       case STREAM_ENCRYPTED_SESSION_DATA:
303          Dmsg1(30, "Stream=Encrypted Session Data, size: %d\n", sd->msglen);
304          /* Save session keys . */
305          switch(crypto_session_decode(sd->msg, (size_t) sd->msglen, jcr->pki_recipients, &cs)) {
306          case CRYPTO_ERROR_NONE:
307             /* Success */
308             break;
309          case CRYPTO_ERROR_NORECIPIENT:
310             Jmsg(jcr, M_ERROR, 0, _("Missing private key required to decrypt encrypted backup data."));
311             break;
312          case CRYPTO_ERROR_DECRYPTION:
313             Jmsg(jcr, M_ERROR, 0, _("Decrypt of the session key failed."));
314             break;
315          default:
316             /* Shouldn't happen */
317             Jmsg(jcr, M_ERROR, 0, _("An error occured while decoding encrypted session data stream."));
318             break;
319          }
320
321          break;
322
323       case STREAM_FILE_DATA:
324       case STREAM_SPARSE_DATA:
325       case STREAM_WIN32_DATA:
326       case STREAM_GZIP_DATA:
327       case STREAM_SPARSE_GZIP_DATA:
328       case STREAM_WIN32_GZIP_DATA:
329          /* Force an expected, consistent stream type here */
330          if (extract && (prev_stream == stream || prev_stream == STREAM_UNIX_ATTRIBUTES
331                   || prev_stream == STREAM_UNIX_ATTRIBUTES_EX
332                   || prev_stream == STREAM_ENCRYPTED_SESSION_DATA)) {
333             flags = 0;
334             if (stream == STREAM_SPARSE_DATA || stream == STREAM_SPARSE_GZIP_DATA) {
335                flags |= FO_SPARSE;
336             }
337             if (stream == STREAM_GZIP_DATA || stream == STREAM_SPARSE_GZIP_DATA
338                   || stream == STREAM_WIN32_GZIP_DATA) {
339                flags |= FO_GZIP;
340             }
341
342             if (is_win32_stream(stream) && !have_win32_api()) {
343                set_portable_backup(&bfd);
344                flags |= FO_WIN32DECOMP;    /* "decompose" BackupWrite data */
345             }
346
347             if (extract_data(jcr, &bfd, sd->msg, sd->msglen, &fileAddr, flags) < 0) {
348                extract = false;
349                bclose(&bfd);
350                continue;
351             }
352          }
353          break;
354
355       /* Resource fork stream - only recorded after a file to be restored */
356       /* Silently ignore if we cannot write - we already reported that */
357       case STREAM_MACOS_FORK_DATA:
358 #ifdef HAVE_DARWIN_OS
359          if (extract) {
360             if (prev_stream != stream) {
361                if (bopen_rsrc(&altbfd, jcr->last_fname, O_WRONLY | O_TRUNC | O_BINARY, 0) < 0) {
362                   Jmsg(jcr, M_ERROR, 0, _("     Cannot open resource fork for %s.\n"), jcr->last_fname);
363                   extract = false;
364                   continue;
365                }
366                alt_size = rsrc_len;
367                Dmsg0(30, "Restoring resource fork\n");
368             }
369             flags = 0;
370             if (extract_data(jcr, &altbfd, sd->msg, sd->msglen, &alt_addr, flags) < 0) {
371                extract = false;
372                bclose(&altbfd);
373                continue;
374             }
375          }
376 #else
377          non_support_rsrc++;
378 #endif
379          break;
380
381       case STREAM_HFSPLUS_ATTRIBUTES:
382 #ifdef HAVE_DARWIN_OS
383          Dmsg0(30, "Restoring Finder Info\n");
384          if (sd->msglen != 32) {
385             Jmsg(jcr, M_ERROR, 0, _("     Invalid length of Finder Info (got %d, not 32)\n"), sd->msglen);
386             continue;
387          }
388          if (setattrlist(jcr->last_fname, &attrList, sd->msg, sd->msglen, 0) != 0) {
389             Jmsg(jcr, M_ERROR, 0, _("     Could not set Finder Info on %s\n"), jcr->last_fname);
390             continue;
391          }
392 #else
393          non_support_finfo++;
394 #endif
395
396       case STREAM_UNIX_ATTRIBUTES_ACCESS_ACL:
397 #ifdef HAVE_ACL
398          pm_strcpy(jcr->acl_text, sd->msg);
399          Dmsg2(400, "Restoring ACL type 0x%2x <%s>\n", BACL_TYPE_ACCESS, jcr->acl_text);
400          if (bacl_set(jcr, BACL_TYPE_ACCESS) != 0) {
401                Qmsg1(jcr, M_WARNING, 0, _("Can't restore ACL of %s\n"), jcr->last_fname);
402          }
403 #else 
404          non_support_acl++;
405 #endif
406          break;
407
408       case STREAM_UNIX_ATTRIBUTES_DEFAULT_ACL:
409 #ifdef HAVE_ACL
410          pm_strcpy(jcr->acl_text, sd->msg);
411          Dmsg2(400, "Restoring ACL type 0x%2x <%s>\n", BACL_TYPE_DEFAULT, jcr->acl_text);
412          if (bacl_set(jcr, BACL_TYPE_DEFAULT) != 0) {
413                Qmsg1(jcr, M_WARNING, 0, _("Can't restore default ACL of %s\n"), jcr->last_fname);
414          }
415 #else 
416          non_support_acl++;
417 #endif
418          break;
419
420       case STREAM_SIGNED_DIGEST:
421          /* Save signature. */
422          sig = crypto_sign_decode(sd->msg, (size_t) sd->msglen);
423          break;
424
425       case STREAM_MD5_DIGEST:
426       case STREAM_SHA1_DIGEST:
427       case STREAM_SHA256_DIGEST:
428       case STREAM_SHA512_DIGEST:
429          break;
430
431       case STREAM_PROGRAM_NAMES:
432       case STREAM_PROGRAM_DATA:
433          if (!non_support_progname) {
434             Pmsg0(000, "Got Program Name or Data Stream. Ignored.\n");
435             non_support_progname++;
436          }
437          break;
438
439       default:
440          /* If extracting, wierd stream (not 1 or 2), close output file anyway */
441          if (extract) {
442             Dmsg1(30, "Found wierd stream %d\n", stream);
443             if (size > 0 && !is_bopen(&bfd)) {
444                Jmsg0(jcr, M_ERROR, 0, _("Logic error: output file should be open\n"));
445             }
446             set_attributes(jcr, attr, &bfd);
447             extract = false;
448          } else if (is_bopen(&bfd)) {
449             Jmsg0(jcr, M_ERROR, 0, _("Logic error: output file should not be open\n"));
450             bclose(&bfd);
451          }
452          Jmsg(jcr, M_ERROR, 0, _("Unknown stream=%d ignored. This shouldn't happen!\n"), stream);
453          Dmsg2(0, "None of above!!! stream=%d data=%s\n", stream,sd->msg);
454          break;
455       } /* end switch(stream) */
456
457    } /* end while get_msg() */
458
459    /* If output file is still open, it was the last one in the
460     * archive since we just hit an end of file, so close the file.
461     */
462    if (is_bopen(&altbfd)) {
463       bclose_chksize(jcr, &altbfd, alt_size);
464       /* Verify the cryptographic signature on the last file, if any */
465       if (jcr->pki_sign) {
466          if (sig) {
467             // Failure is reported in verify_signature() ...
468             verify_signature(jcr, sig);
469          } else {
470             Jmsg1(jcr, M_ERROR, 0, _("Missing cryptographic signature for %s\n"), jcr->last_fname);
471          }
472       }
473    }
474    if (extract) {
475       set_attributes(jcr, attr, &bfd);
476    }
477    if (is_bopen(&bfd)) {
478       bclose(&bfd);
479    }
480    set_jcr_job_status(jcr, JS_Terminated);
481    goto ok_out;
482
483 bail_out:
484    set_jcr_job_status(jcr, JS_ErrorTerminated);
485 ok_out:
486
487    /* Free Signature & Crypto Session */
488    if (sig) {
489       crypto_sign_free(sig);
490       sig = NULL;
491    }
492    if (cs) {
493       crypto_session_free(cs);
494       cs = NULL;
495    }
496    if (jcr->compress_buf) {
497       free(jcr->compress_buf);
498       jcr->compress_buf = NULL;
499       jcr->compress_buf_size = 0;
500    }
501    bclose(&altbfd);
502    bclose(&bfd);
503    free_attr(attr);
504    free_pool_memory(jcr->acl_text);
505    Dmsg2(10, "End Do Restore. Files=%d Bytes=%s\n", jcr->JobFiles,
506       edit_uint64(jcr->JobBytes, ec1));
507    if (non_support_data > 1 || non_support_attr > 1) {
508       Jmsg(jcr, M_ERROR, 0, _("%d non-supported data streams and %d non-supported attrib streams ignored.\n"),
509          non_support_data, non_support_attr);
510    }
511    if (non_support_rsrc) {
512       Jmsg(jcr, M_INFO, 0, _("%d non-supported resource fork streams ignored.\n"), non_support_rsrc);
513    }
514    if (non_support_finfo) {
515       Jmsg(jcr, M_INFO, 0, _("%d non-supported Finder Info streams ignored.\n"), non_support_rsrc);
516    }
517    if (non_support_acl) {
518       Jmsg(jcr, M_INFO, 0, _("%d non-supported acl streams ignored.\n"), non_support_acl);
519    }
520
521 }
522
523 #ifdef HAVE_LIBZ
524 /*
525  * Convert ZLIB error code into an ASCII message
526  */
527 static const char *zlib_strerror(int stat)
528 {
529    if (stat >= 0) {
530       return _("None");
531    }
532    switch (stat) {
533    case Z_ERRNO:
534       return _("Zlib errno");
535    case Z_STREAM_ERROR:
536       return _("Zlib stream error");
537    case Z_DATA_ERROR:
538       return _("Zlib data error");
539    case Z_MEM_ERROR:
540       return _("Zlib memory error");
541    case Z_BUF_ERROR:
542       return _("Zlib buffer error");
543    case Z_VERSION_ERROR:
544       return _("Zlib version error");
545    default:
546       return _("*none*");
547    }
548 }
549 #endif
550
551 static int do_file_digest(FF_PKT *ff_pkt, void *pkt, bool top_level) {
552    JCR *jcr = (JCR *) pkt;
553    return (digest_file(jcr, ff_pkt, jcr->digest));
554 }
555
556 /*
557  * Verify the signature for the last restored file
558  * Return value is either true (signature correct)
559  * or false (signature could not be verified).
560  * TODO landonf: Better signature failure handling.
561  */
562 int verify_signature(JCR *jcr, SIGNATURE *sig)
563 {
564    X509_KEYPAIR *keypair;
565    DIGEST *digest = NULL;
566    crypto_error_t err;
567
568    /* Iterate through the trusted signers */
569    foreach_alist(keypair, jcr->pki_signers) {
570       err = crypto_sign_get_digest(sig, jcr->pki_keypair, &digest);
571
572       switch (err) {
573       case CRYPTO_ERROR_NONE:
574          /* Signature found, digest allocated */
575          jcr->digest = digest;
576
577          /* Checksum the entire file */
578          if (find_one_file(jcr, jcr->ff, do_file_digest, jcr, jcr->last_fname, (dev_t)-1, 1) != 0) {
579             Qmsg(jcr, M_ERROR, 0, _("Signature validation failed for %s: \n"), jcr->last_fname);
580             return false;
581          }
582
583          /* Verify the signature */
584          if ((err = crypto_sign_verify(sig, keypair, digest)) != CRYPTO_ERROR_NONE) {
585             Dmsg1(100, "Bad signature on %s\n", jcr->last_fname);
586             Qmsg2(jcr, M_ERROR, 0, _("Signature validation failed for %s: %s\n"), jcr->last_fname, crypto_strerror(err));
587             crypto_digest_free(digest);
588             return false;
589          }
590
591          /* Valid signature */
592          Dmsg1(100, "Signature good on %s\n", jcr->last_fname);
593          crypto_digest_free(digest);
594          return true;
595
596       case CRYPTO_ERROR_NOSIGNER:
597          /* Signature not found, try again */
598          continue;
599       default:
600          /* Something strange happened (that shouldn't happen!)... */
601          Qmsg2(jcr, M_ERROR, 0, _("Signature validation failed for %s: %s\n"), jcr->last_fname, crypto_strerror(err));
602          if (digest) {
603             crypto_digest_free(digest);
604          }
605          return false;
606       }
607    }
608
609    /* No signer */
610    Dmsg1(100, "Could not find a valid public key for signature on %s\n", jcr->last_fname);
611    crypto_digest_free(digest);
612    return false;
613 }
614
615 /*
616  * In the context of jcr, write data to bfd.
617  * We write buflen bytes in buf at addr. addr is updated in place.
618  * The flags specify whether to use sparse files or compression.
619  * Return value is the number of bytes written, or -1 on errors.
620  */
621 int32_t extract_data(JCR *jcr, BFILE *bfd, POOLMEM *buf, int32_t buflen,
622       uint64_t *addr, int flags)
623 {
624    int stat;
625    char *wbuf;                        /* write buffer */
626    uint32_t wsize;                    /* write size */
627    uint32_t rsize;                    /* read size */
628    char ec1[50];                      /* Buffer printing huge values */
629
630    if (flags & FO_SPARSE) {
631       ser_declare;
632       uint64_t faddr;
633       char ec1[50];
634       wbuf = buf + SPARSE_FADDR_SIZE;
635       rsize = buflen - SPARSE_FADDR_SIZE;
636       ser_begin(buf, SPARSE_FADDR_SIZE);
637       unser_uint64(faddr);
638       if (*addr != faddr) {
639          *addr = faddr;
640          if (blseek(bfd, (off_t)*addr, SEEK_SET) < 0) {
641             berrno be;
642             Jmsg3(jcr, M_ERROR, 0, _("Seek to %s error on %s: ERR=%s\n"),
643                   edit_uint64(*addr, ec1), jcr->last_fname, 
644                   be.strerror(bfd->berrno));
645             return -1;
646          }
647       }
648    } else {
649       wbuf = buf;
650       rsize = buflen;
651    }
652    wsize = rsize;
653
654    if (flags & FO_GZIP) {
655 #ifdef HAVE_LIBZ
656       uLong compress_len;
657       /* 
658        * NOTE! We only use uLong and Byte because they are
659        *  needed by the zlib routines, they should not otherwise
660        *  be used in Bacula.
661        */
662       compress_len = jcr->compress_buf_size;
663       Dmsg2(100, "Comp_len=%d msglen=%d\n", compress_len, wsize);
664       if ((stat=uncompress((Byte *)jcr->compress_buf, &compress_len,
665                   (const Byte *)wbuf, (uLong)rsize)) != Z_OK) {
666          Qmsg(jcr, M_ERROR, 0, _("Uncompression error on file %s. ERR=%s\n"),
667                jcr->last_fname, zlib_strerror(stat));
668          return -1;
669       }
670       wbuf = jcr->compress_buf;
671       wsize = compress_len;
672       Dmsg2(100, "Write uncompressed %d bytes, total before write=%s\n", compress_len, edit_uint64(jcr->JobBytes, ec1));
673 #else
674       Qmsg(jcr, M_ERROR, 0, _("GZIP data stream found, but GZIP not configured!\n"));
675       return -1;
676 #endif
677    } else {
678       Dmsg2(30, "Write %u bytes, total before write=%s\n", wsize, edit_uint64(jcr->JobBytes, ec1));
679    }
680
681    if (flags & FO_WIN32DECOMP) {
682       if (!processWin32BackupAPIBlock(bfd, wbuf, wsize)) {
683          berrno be;
684          Jmsg2(jcr, M_ERROR, 0, _("Write error in Win32 Block Decomposition on %s: %s\n"), 
685                jcr->last_fname, be.strerror(bfd->berrno));
686          return -1;
687       }
688    } else if (bwrite(bfd, wbuf, wsize) != (ssize_t)wsize) {
689       berrno be;
690       Jmsg2(jcr, M_ERROR, 0, _("Write error on %s: %s\n"), 
691             jcr->last_fname, be.strerror(bfd->berrno));
692       return -1;
693    }
694
695    jcr->JobBytes += wsize;
696    jcr->ReadBytes += rsize;
697    *addr += wsize;
698
699    return wsize;
700 }