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