]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/stored/bextract.c
Fix brestore compilation from previous patch
[bacula/bacula] / bacula / src / stored / bextract.c
1 /*
2    Bacula® - The Network Backup Solution
3
4    Copyright (C) 2000-2011 Free Software Foundation Europe e.V.
5
6    The main author of Bacula is Kern Sibbald, with contributions from
7    many others, a complete list can be found in the file AUTHORS.
8    This program is Free Software; you can redistribute it and/or
9    modify it under the terms of version three of the GNU Affero General Public
10    License as published by the Free Software Foundation and included
11    in the file LICENSE.
12
13    This program is distributed in the hope that it will be useful, but
14    WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16    General Public License for more details.
17
18    You should have received a copy of the GNU Affero General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21    02110-1301, USA.
22
23    Bacula® is a registered trademark of Kern Sibbald.
24    The licensor of Bacula is the Free Software Foundation Europe
25    (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
26    Switzerland, email:ftf@fsfeurope.org.
27 */
28 /*
29  *
30  *  Dumb program to extract files from a Bacula backup.
31  *
32  *   Kern E. Sibbald, MM
33  *
34  */
35
36 #include "bacula.h"
37 #include "stored.h"
38 #include "ch.h"
39 #include "findlib/find.h"
40
41 extern bool parse_sd_config(CONFIG *config, const char *configfile, int exit_code);
42
43 static void do_extract(char *fname);
44 static bool record_cb(DCR *dcr, DEV_RECORD *rec);
45
46 static DEVICE *dev = NULL;
47 static DCR *dcr;
48 static BFILE bfd;
49 static JCR *jcr;
50 static FF_PKT *ff;
51 static BSR *bsr = NULL;
52 static bool extract = false;
53 static int non_support_data = 0;
54 static long total = 0;
55 static ATTR *attr;
56 static char *where;
57 static uint32_t num_files = 0;
58 static uint32_t compress_buf_size = 70000;
59 static POOLMEM *compress_buf;
60 static int prog_name_msg = 0;
61 static int win32_data_msg = 0;
62 static char *VolumeName = NULL;
63
64 static char *wbuf;                    /* write buffer address */
65 static uint32_t wsize;                /* write size */
66 static uint64_t fileAddr = 0;         /* file write address */
67
68 static CONFIG *config;
69 #define CONFIG_FILE "bacula-sd.conf"
70 char *configfile = NULL;
71 STORES *me = NULL;                    /* our Global resource */
72 bool forge_on = false;
73 pthread_mutex_t device_release_mutex = PTHREAD_MUTEX_INITIALIZER;
74 pthread_cond_t wait_device_release = PTHREAD_COND_INITIALIZER;
75
76 static void usage()
77 {
78    fprintf(stderr, _(
79 PROG_COPYRIGHT
80 "\nVersion: %s (%s)\n\n"
81 "Usage: bextract <options> <bacula-archive-device-name> <directory-to-store-files>\n"
82 "       -b <file>       specify a bootstrap file\n"
83 "       -c <file>       specify a Storage configuration file\n"
84 "       -d <nn>         set debug level to <nn>\n"
85 "       -dt             print timestamp in debug output\n"
86 "       -e <file>       exclude list\n"
87 "       -i <file>       include list\n"
88 "       -p              proceed inspite of I/O errors\n"
89 "       -v              verbose\n"
90 "       -V <volumes>    specify Volume names (separated by |)\n"
91 "       -?              print this message\n\n"), 2000, VERSION, BDATE);
92    exit(1);
93 }
94
95
96 int main (int argc, char *argv[])
97 {
98    int ch;
99    FILE *fd;
100    char line[1000];
101    bool got_inc = false;
102
103    setlocale(LC_ALL, "");
104    bindtextdomain("bacula", LOCALEDIR);
105    textdomain("bacula");
106    init_stack_dump();
107    lmgr_init_thread();
108
109    working_directory = "/tmp";
110    my_name_is(argc, argv, "bextract");
111    init_msg(NULL, NULL);              /* setup message handler */
112
113    OSDependentInit();
114
115    ff = init_find_files();
116    binit(&bfd);
117
118    while ((ch = getopt(argc, argv, "b:c:d:e:i:pvV:?")) != -1) {
119       switch (ch) {
120       case 'b':                    /* bootstrap file */
121          bsr = parse_bsr(NULL, optarg);
122 //       dump_bsr(bsr, true);
123          break;
124
125       case 'c':                    /* specify config file */
126          if (configfile != NULL) {
127             free(configfile);
128          }
129          configfile = bstrdup(optarg);
130          break;
131
132       case 'd':                    /* debug level */
133          if (*optarg == 't') {
134             dbg_timestamp = true;
135          } else {
136             debug_level = atoi(optarg);
137             if (debug_level <= 0) {
138                debug_level = 1;
139             }
140          }
141          break;
142
143       case 'e':                    /* exclude list */
144          if ((fd = fopen(optarg, "rb")) == NULL) {
145             berrno be;
146             Pmsg2(0, _("Could not open exclude file: %s, ERR=%s\n"),
147                optarg, be.bstrerror());
148             exit(1);
149          }
150          while (fgets(line, sizeof(line), fd) != NULL) {
151             strip_trailing_junk(line);
152             Dmsg1(900, "add_exclude %s\n", line);
153             add_fname_to_exclude_list(ff, line);
154          }
155          fclose(fd);
156          break;
157
158       case 'i':                    /* include list */
159          if ((fd = fopen(optarg, "rb")) == NULL) {
160             berrno be;
161             Pmsg2(0, _("Could not open include file: %s, ERR=%s\n"),
162                optarg, be.bstrerror());
163             exit(1);
164          }
165          while (fgets(line, sizeof(line), fd) != NULL) {
166             strip_trailing_junk(line);
167             Dmsg1(900, "add_include %s\n", line);
168             add_fname_to_include_list(ff, 0, line);
169          }
170          fclose(fd);
171          got_inc = true;
172          break;
173
174       case 'p':
175          forge_on = true;
176          break;
177
178       case 'v':
179          verbose++;
180          break;
181
182       case 'V':                    /* Volume name */
183          VolumeName = optarg;
184          break;
185
186       case '?':
187       default:
188          usage();
189
190       } /* end switch */
191    } /* end while */
192    argc -= optind;
193    argv += optind;
194
195    if (argc != 2) {
196       Pmsg0(0, _("Wrong number of arguments: \n"));
197       usage();
198    }
199
200    if (configfile == NULL) {
201       configfile = bstrdup(CONFIG_FILE);
202    }
203
204    config = new_config_parser();
205    parse_sd_config(config, configfile, M_ERROR_TERM);
206
207    if (!got_inc) {                            /* If no include file, */
208       add_fname_to_include_list(ff, 0, "/");  /*   include everything */
209    }
210
211    where = argv[1];
212    do_extract(argv[0]);
213
214    if (bsr) {
215       free_bsr(bsr);
216    }
217    if (prog_name_msg) {
218       Pmsg1(000, _("%d Program Name and/or Program Data Stream records ignored.\n"),
219          prog_name_msg);
220    }
221    if (win32_data_msg) {
222       Pmsg1(000, _("%d Win32 data or Win32 gzip data stream records. Ignored.\n"),
223          win32_data_msg);
224    }
225    term_include_exclude_files(ff);
226    term_find_files(ff);
227    return 0;
228 }
229
230 static void do_extract(char *devname)
231 {
232    struct stat statp;
233
234    enable_backup_privileges(NULL, 1);
235
236    jcr = setup_jcr("bextract", devname, bsr, VolumeName, 1); /* acquire for read */
237    if (!jcr) {
238       exit(1);
239    }
240    dev = jcr->read_dcr->dev;
241    if (!dev) {
242       exit(1);
243    }
244    dcr = jcr->read_dcr;
245
246    /* Make sure where directory exists and that it is a directory */
247    if (stat(where, &statp) < 0) {
248       berrno be;
249       Emsg2(M_ERROR_TERM, 0, _("Cannot stat %s. It must exist. ERR=%s\n"),
250          where, be.bstrerror());
251    }
252    if (!S_ISDIR(statp.st_mode)) {
253       Emsg1(M_ERROR_TERM, 0, _("%s must be a directory.\n"), where);
254    }
255
256    free(jcr->where);
257    jcr->where = bstrdup(where);
258    attr = new_attr(jcr);
259
260    compress_buf = get_memory(compress_buf_size);
261
262    read_records(dcr, record_cb, mount_next_read_volume);
263    /* If output file is still open, it was the last one in the
264     * archive since we just hit an end of file, so close the file.
265     */
266    if (is_bopen(&bfd)) {
267       set_attributes(jcr, attr, &bfd);
268    }
269    release_device(dcr);
270    free_attr(attr);
271    free_jcr(jcr);
272    dev->term();
273
274    printf(_("%u files restored.\n"), num_files);
275    return;
276 }
277
278 static bool store_data(BFILE *bfd, char *data, const int32_t length)
279 {
280    if (is_win32_stream(attr->data_stream) && !have_win32_api()) {
281       set_portable_backup(bfd);
282       if (!processWin32BackupAPIBlock(bfd, data, length)) {
283          berrno be;
284          Emsg2(M_ERROR_TERM, 0, _("Write error on %s: %s\n"),
285                attr->ofname, be.bstrerror());
286          return false;
287       }
288    } else if (bwrite(bfd, data, length) != (ssize_t)length) {
289       berrno be;
290       Emsg2(M_ERROR_TERM, 0, _("Write error on %s: %s\n"),
291             attr->ofname, be.bstrerror());
292       return false;
293    }
294
295    return true;
296 }
297
298 /*
299  * Called here for each record from read_records()
300  */
301 static bool record_cb(DCR *dcr, DEV_RECORD *rec)
302 {
303    int stat;
304    JCR *jcr = dcr->jcr;
305
306    if (rec->FileIndex < 0) {
307       return true;                    /* we don't want labels */
308    }
309
310    /* File Attributes stream */
311
312    switch (rec->maskedStream) {
313    case STREAM_UNIX_ATTRIBUTES:
314    case STREAM_UNIX_ATTRIBUTES_EX:
315
316       /* If extracting, it was from previous stream, so
317        * close the output file.
318        */
319       if (extract) {
320          if (!is_bopen(&bfd)) {
321             Emsg0(M_ERROR, 0, _("Logic error output file should be open but is not.\n"));
322          }
323          set_attributes(jcr, attr, &bfd);
324          extract = false;
325       }
326
327       if (!unpack_attributes_record(jcr, rec->Stream, rec->data, rec->data_len, attr)) {
328          Emsg0(M_ERROR_TERM, 0, _("Cannot continue.\n"));
329       }
330
331       if (file_is_included(ff, attr->fname) && !file_is_excluded(ff, attr->fname)) {
332          attr->data_stream = decode_stat(attr->attr, &attr->statp, sizeof(attr->statp), &attr->LinkFI);
333          if (!is_restore_stream_supported(attr->data_stream)) {
334             if (!non_support_data++) {
335                Jmsg(jcr, M_ERROR, 0, _("%s stream not supported on this Client.\n"),
336                   stream_to_ascii(attr->data_stream));
337             }
338             extract = false;
339             return true;
340          }
341
342          build_attr_output_fnames(jcr, attr);
343
344          if (attr->type == FT_DELETED) { /* TODO: choose the right fname/ofname */
345             Jmsg(jcr, M_INFO, 0, _("%s was deleted.\n"), attr->fname);
346             extract = false;
347             return true;
348          }
349
350          extract = false;
351          stat = create_file(jcr, attr, &bfd, REPLACE_ALWAYS);
352          switch (stat) {
353          case CF_ERROR:
354          case CF_SKIP:
355             break;
356          case CF_EXTRACT:
357             extract = true;
358             print_ls_output(jcr, attr);
359             num_files++;
360             fileAddr = 0;
361             break;
362          case CF_CREATED:
363             set_attributes(jcr, attr, &bfd);
364             print_ls_output(jcr, attr);
365             num_files++;
366             fileAddr = 0;
367             break;
368          }
369       }
370       break;
371
372    case STREAM_RESTORE_OBJECT:
373       /* nothing to do */
374       break;
375
376    /* Data stream and extracting */
377    case STREAM_FILE_DATA:
378    case STREAM_SPARSE_DATA:
379    case STREAM_WIN32_DATA:
380
381       if (extract) {
382          if (rec->maskedStream == STREAM_SPARSE_DATA) {
383             ser_declare;
384             uint64_t faddr;
385             wbuf = rec->data + OFFSET_FADDR_SIZE;
386             wsize = rec->data_len - OFFSET_FADDR_SIZE;
387             ser_begin(rec->data, OFFSET_FADDR_SIZE);
388             unser_uint64(faddr);
389             if (fileAddr != faddr) {
390                fileAddr = faddr;
391                if (blseek(&bfd, (boffset_t)fileAddr, SEEK_SET) < 0) {
392                   berrno be;
393                   Emsg2(M_ERROR_TERM, 0, _("Seek error on %s: %s\n"),
394                      attr->ofname, be.bstrerror());
395                }
396             }
397          } else {
398             wbuf = rec->data;
399             wsize = rec->data_len;
400          }
401          total += wsize;
402          Dmsg2(8, "Write %u bytes, total=%u\n", wsize, total);
403          store_data(&bfd, wbuf, wsize);
404          fileAddr += wsize;
405       }
406       break;
407
408    /* GZIP data stream */
409    case STREAM_GZIP_DATA:
410    case STREAM_SPARSE_GZIP_DATA:
411    case STREAM_WIN32_GZIP_DATA:
412 #ifdef HAVE_LIBZ
413       if (extract) {
414          uLong compress_len = compress_buf_size;
415          int stat = Z_BUF_ERROR;
416
417          if (rec->maskedStream == STREAM_SPARSE_GZIP_DATA) {
418             ser_declare;
419             uint64_t faddr;
420             char ec1[50];
421             wbuf = rec->data + OFFSET_FADDR_SIZE;
422             wsize = rec->data_len - OFFSET_FADDR_SIZE;
423             ser_begin(rec->data, OFFSET_FADDR_SIZE);
424             unser_uint64(faddr);
425             if (fileAddr != faddr) {
426                fileAddr = faddr;
427                if (blseek(&bfd, (boffset_t)fileAddr, SEEK_SET) < 0) {
428                   berrno be;
429                   Emsg3(M_ERROR, 0, _("Seek to %s error on %s: ERR=%s\n"),
430                      edit_uint64(fileAddr, ec1), attr->ofname, be.bstrerror());
431                   extract = false;
432                   return true;
433                }
434             }
435          } else {
436             wbuf = rec->data;
437             wsize = rec->data_len;
438          }
439
440          while (compress_len < 10000000 && (stat=uncompress((Byte *)compress_buf, &compress_len,
441                                  (const Byte *)wbuf, (uLong)wsize)) == Z_BUF_ERROR) {
442             /* The buffer size is too small, try with a bigger one */
443             compress_len = 2 * compress_len;
444             compress_buf = check_pool_memory_size(compress_buf,
445                                                   compress_len);
446          }
447          if (stat != Z_OK) {
448             Emsg1(M_ERROR, 0, _("Uncompression error. ERR=%d\n"), stat);
449             extract = false;
450             return true;
451          }
452
453          Dmsg2(100, "Write uncompressed %d bytes, total before write=%d\n", compress_len, total);
454          store_data(&bfd, compress_buf, compress_len);
455          total += compress_len;
456          fileAddr += compress_len;
457          Dmsg2(100, "Compress len=%d uncompressed=%d\n", rec->data_len,
458             compress_len);
459       }
460 #else
461       if (extract) {
462          Emsg0(M_ERROR, 0, _("GZIP data stream found, but GZIP not configured!\n"));
463          extract = false;
464          return true;
465       }
466 #endif
467       break;
468
469    /* Compressed data stream */
470    case STREAM_COMPRESSED_DATA:
471    case STREAM_SPARSE_COMPRESSED_DATA:
472    case STREAM_WIN32_COMPRESSED_DATA:
473       if (extract) {
474          uint32_t comp_magic, comp_len;
475          uint16_t comp_level, comp_version;
476 #ifdef HAVE_LZO
477          lzo_uint compress_len;
478          const unsigned char *cbuf;
479          int r, real_compress_len;
480 #endif
481
482          if (rec->maskedStream == STREAM_SPARSE_COMPRESSED_DATA) {
483             ser_declare;
484             uint64_t faddr;
485             char ec1[50];
486             wbuf = rec->data + OFFSET_FADDR_SIZE;
487             wsize = rec->data_len - OFFSET_FADDR_SIZE;
488             ser_begin(rec->data, OFFSET_FADDR_SIZE);
489             unser_uint64(faddr);
490             if (fileAddr != faddr) {
491                fileAddr = faddr;
492                if (blseek(&bfd, (boffset_t)fileAddr, SEEK_SET) < 0) {
493                   berrno be;
494                   Emsg3(M_ERROR, 0, _("Seek to %s error on %s: ERR=%s\n"),
495                      edit_uint64(fileAddr, ec1), attr->ofname, be.bstrerror());
496                   extract = false;
497                   return true;
498                }
499             }
500          } else {
501             wbuf = rec->data;
502             wsize = rec->data_len;
503          }
504
505          /* read compress header */
506          unser_declare;
507          unser_begin(wbuf, sizeof(comp_stream_header));
508          unser_uint32(comp_magic);
509          unser_uint32(comp_len);
510          unser_uint16(comp_level);
511          unser_uint16(comp_version);
512          Dmsg4(200, "Compressed data stream found: magic=0x%x, len=%d, level=%d, ver=0x%x\n", comp_magic, comp_len,
513                                  comp_level, comp_version);
514
515          /* version check */
516          if (comp_version != COMP_HEAD_VERSION) {
517             Emsg1(M_ERROR, 0, _("Compressed header version error. version=0x%x\n"), comp_version);
518             return false;
519          }
520          /* size check */
521          if (comp_len + sizeof(comp_stream_header) != wsize) {
522             Emsg2(M_ERROR, 0, _("Compressed header size error. comp_len=%d, msglen=%d\n"),
523                  comp_len, wsize);
524             return false;
525          }
526
527           switch(comp_magic) {
528 #ifdef HAVE_LZO
529             case COMPRESS_LZO1X:
530                compress_len = compress_buf_size;
531                cbuf = (const unsigned char*) wbuf + sizeof(comp_stream_header);
532                real_compress_len = wsize - sizeof(comp_stream_header);
533                Dmsg2(200, "Comp_len=%d msglen=%d\n", compress_len, wsize);
534                while ((r=lzo1x_decompress_safe(cbuf, real_compress_len,
535                                                (unsigned char *)compress_buf, &compress_len, NULL)) == LZO_E_OUTPUT_OVERRUN)
536                {
537
538                   /* The buffer size is too small, try with a bigger one */
539                   compress_len = 2 * compress_len;
540                   compress_buf = check_pool_memory_size(compress_buf,
541                                                   compress_len);
542                }
543                if (r != LZO_E_OK) {
544                   Emsg1(M_ERROR, 0, _("LZO uncompression error. ERR=%d\n"), r);
545                   extract = false;
546                   return true;
547                }
548                Dmsg2(100, "Write uncompressed %d bytes, total before write=%d\n", compress_len, total);
549                store_data(&bfd, compress_buf, compress_len);
550                total += compress_len;
551                fileAddr += compress_len;
552                Dmsg2(100, "Compress len=%d uncompressed=%d\n", rec->data_len, compress_len);
553                break;
554 #endif
555             default:
556                Emsg1(M_ERROR, 0, _("Compression algorithm 0x%x found, but not supported!\n"), comp_magic);
557                extract = false;
558                return true;
559          }
560
561       }
562       break;
563
564    case STREAM_MD5_DIGEST:
565    case STREAM_SHA1_DIGEST:
566    case STREAM_SHA256_DIGEST:
567    case STREAM_SHA512_DIGEST:
568       break;
569
570    case STREAM_SIGNED_DIGEST:
571    case STREAM_ENCRYPTED_SESSION_DATA:
572       // TODO landonf: Investigate crypto support in the storage daemon
573       break;
574
575    case STREAM_PROGRAM_NAMES:
576    case STREAM_PROGRAM_DATA:
577       if (!prog_name_msg) {
578          Pmsg0(000, _("Got Program Name or Data Stream. Ignored.\n"));
579          prog_name_msg++;
580       }
581       break;
582
583    default:
584       /* If extracting, weird stream (not 1 or 2), close output file anyway */
585       if (extract) {
586          if (!is_bopen(&bfd)) {
587             Emsg0(M_ERROR, 0, _("Logic error output file should be open but is not.\n"));
588          }
589          set_attributes(jcr, attr, &bfd);
590          extract = false;
591       }
592       Jmsg(jcr, M_ERROR, 0, _("Unknown stream=%d ignored. This shouldn't happen!\n"),
593          rec->Stream);
594       break;
595
596    } /* end switch */
597    return true;
598 }
599
600 /* Dummies to replace askdir.c */
601 bool    dir_find_next_appendable_volume(DCR *dcr) { return 1;}
602 bool    dir_update_volume_info(DCR *dcr, bool relabel, bool update_LastWritten) { return 1; }
603 bool    dir_create_jobmedia_record(DCR *dcr, bool zero) { return 1; }
604 bool    dir_ask_sysop_to_create_appendable_volume(DCR *dcr) { return 1; }
605 bool    dir_update_file_attributes(DCR *dcr, DEV_RECORD *rec) { return 1;}
606 bool    dir_send_job_status(JCR *jcr) {return 1;}
607
608
609 bool dir_ask_sysop_to_mount_volume(DCR *dcr, int /*mode*/)
610 {
611    DEVICE *dev = dcr->dev;
612    fprintf(stderr, _("Mount Volume \"%s\" on device %s and press return when ready: "),
613       dcr->VolumeName, dev->print_name());
614    dev->close();
615    getchar();
616    return true;
617 }
618
619 bool dir_get_volume_info(DCR *dcr, enum get_vol_info_rw  writing)
620 {
621    Dmsg0(100, "Fake dir_get_volume_info\n");
622    dcr->setVolCatName(dcr->VolumeName);
623    dcr->VolCatInfo.VolCatParts = find_num_dvd_parts(dcr);
624    Dmsg2(500, "Vol=%s num_parts=%d\n", dcr->getVolCatName(), dcr->VolCatInfo.VolCatParts);
625    return 1;
626 }