1 /*
2 BAREOS® - Backup Archiving REcovery Open Sourced
3
4 Copyright (C) 2000-2011 Free Software Foundation Europe e.V.
5 Copyright (C) 2011-2012 Planets Communications B.V.
6 Copyright (C) 2013-2020 Bareos GmbH & Co. KG
7
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 Affero 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 /*
24 * Kern E. Sibbald, MM
25 */
26 /**
27 * @file
28 * Dumb program to extract files from a Bareos backup.
29 */
30
31 #include "include/bareos.h"
32 #include "stored/stored.h"
33 #include "stored/stored_globals.h"
34 #include "lib/crypto_cache.h"
35 #include "stored/acquire.h"
36 #include "stored/butil.h"
37 #include "stored/jcr_private.h"
38 #include "stored/mount.h"
39 #include "stored/read_record.h"
40 #include "findlib/find.h"
41 #include "findlib/attribs.h"
42 #include "findlib/create_file.h"
43 #include "findlib/match.h"
44 #include "findlib/get_priv.h"
45 #include "lib/address_conf.h"
46 #include "lib/attribs.h"
47 #include "lib/berrno.h"
48 #include "lib/edit.h"
49 #include "lib/bsignal.h"
50 #include "lib/parse_bsr.h"
51 #include "lib/parse_conf.h"
52 #include "include/jcr.h"
53
54 namespace storagedaemon {
55 extern bool ParseSdConfig(const char* configfile, int exit_code);
56 }
57
58 using namespace storagedaemon;
59
60 static void DoExtract(char* devname);
61 static bool RecordCb(DeviceControlRecord* dcr, DeviceRecord* rec);
62
63 static Device* dev = NULL;
64 static DeviceControlRecord* dcr;
65 static BareosWinFilePacket bfd;
66 static JobControlRecord* jcr;
67 static FindFilesPacket* ff;
68 static BootStrapRecord* bsr = NULL;
69 static bool extract = false;
70 static int non_support_data = 0;
71 static long total = 0;
72 static Attributes* attr;
73 static char* where;
74 static uint32_t num_files = 0;
75 static int prog_name_msg = 0;
76 static int win32_data_msg = 0;
77 static char* VolumeName = NULL;
78 static char* DirectorName = NULL;
79 static DirectorResource* director = NULL;
80
81 static AclData acl_data;
82 static XattrData xattr_data;
83 static alist* delayed_streams = NULL;
84
85 static char* wbuf; /* write buffer address */
86 static uint32_t wsize; /* write size */
87 static uint64_t fileAddr = 0; /* file write address */
88
usage()89 static void usage()
90 {
91 kBareosVersionStrings.PrintCopyrightWithFsfAndPlanets(stderr, 2000);
92 fprintf(stderr,
93 _("Usage: bextract <options> <bareos-archive-device-name> "
94 "<directory-to-store-files>\n"
95 " -b <file> specify a bootstrap file\n"
96 " -c <path> specify a Storage configuration file or "
97 "directory\n"
98 " -D <director> specify a director name specified in the "
99 "Storage\n"
100 " configuration file for the Key Encryption "
101 "Key selection\n"
102 " -d <nn> set debug level to <nn>\n"
103 " -dt print timestamp in debug output\n"
104 " -e <file> exclude list\n"
105 " -i <file> include list\n"
106 " -p proceed inspite of I/O errors\n"
107 " -v verbose\n"
108 " -V <volumes> specify Volume names (separated by |)\n"
109 " -? print this message\n\n"));
110 exit(1);
111 }
112
main(int argc,char * argv[])113 int main(int argc, char* argv[])
114 {
115 int ch;
116 FILE* fd;
117 char line[1000];
118 bool got_inc = false;
119
120 setlocale(LC_ALL, "");
121 tzset();
122 bindtextdomain("bareos", LOCALEDIR);
123 textdomain("bareos");
124 InitStackDump();
125
126 working_directory = "/tmp";
127 MyNameIs(argc, argv, "bextract");
128 InitMsg(NULL, NULL); /* setup message handler */
129
130 OSDependentInit();
131
132 ff = init_find_files();
133 binit(&bfd);
134
135 while ((ch = getopt(argc, argv, "b:c:D:d:e:i:pvV:?")) != -1) {
136 switch (ch) {
137 case 'b': /* bootstrap file */
138 bsr = libbareos::parse_bsr(NULL, optarg);
139 // DumpBsr(bsr, true);
140 break;
141
142 case 'c': /* specify config file */
143 if (configfile != NULL) { free(configfile); }
144 configfile = strdup(optarg);
145 break;
146
147 case 'D': /* specify director name */
148 if (DirectorName != NULL) { free(DirectorName); }
149 DirectorName = strdup(optarg);
150 break;
151
152 case 'd': /* debug level */
153 if (*optarg == 't') {
154 dbg_timestamp = true;
155 } else {
156 debug_level = atoi(optarg);
157 if (debug_level <= 0) { debug_level = 1; }
158 }
159 break;
160
161 case 'e': /* exclude list */
162 if ((fd = fopen(optarg, "rb")) == NULL) {
163 BErrNo be;
164 Pmsg2(0, _("Could not open exclude file: %s, ERR=%s\n"), optarg,
165 be.bstrerror());
166 exit(1);
167 }
168 while (fgets(line, sizeof(line), fd) != NULL) {
169 StripTrailingJunk(line);
170 Dmsg1(900, "add_exclude %s\n", line);
171 AddFnameToExcludeList(ff, line);
172 }
173 fclose(fd);
174 break;
175
176 case 'i': /* include list */
177 if ((fd = fopen(optarg, "rb")) == NULL) {
178 BErrNo be;
179 Pmsg2(0, _("Could not open include file: %s, ERR=%s\n"), optarg,
180 be.bstrerror());
181 exit(1);
182 }
183 while (fgets(line, sizeof(line), fd) != NULL) {
184 StripTrailingJunk(line);
185 Dmsg1(900, "add_include %s\n", line);
186 AddFnameToIncludeList(ff, 0, line);
187 }
188 fclose(fd);
189 got_inc = true;
190 break;
191
192 case 'p':
193 forge_on = true;
194 break;
195
196 case 'v':
197 verbose++;
198 break;
199
200 case 'V': /* Volume name */
201 VolumeName = optarg;
202 break;
203
204 case '?':
205 default:
206 usage();
207
208 } /* end switch */
209 } /* end while */
210 argc -= optind;
211 argv += optind;
212
213 if (argc != 2) {
214 Pmsg0(0,
215 _("Wrong number of arguments. Make sure the last two parameters are "
216 "<bareos-archive-device-name> <directory-to-store-files>\n"));
217 usage();
218 }
219
220 my_config = InitSdConfig(configfile, M_ERROR_TERM);
221 ParseSdConfig(configfile, M_ERROR_TERM);
222
223 if (DirectorName) {
224 foreach_res (director, R_DIRECTOR) {
225 if (bstrcmp(director->resource_name_, DirectorName)) { break; }
226 }
227 if (!director) {
228 Emsg2(
229 M_ERROR_TERM, 0,
230 _("No Director resource named %s defined in %s. Cannot continue.\n"),
231 DirectorName, configfile);
232 }
233 }
234
235 LoadSdPlugins(me->plugin_directory, me->plugin_names);
236
237 ReadCryptoCache(me->working_directory, "bareos-sd",
238 GetFirstPortHostOrder(me->SDaddrs));
239
240 if (!got_inc) { /* If no include file, */
241 AddFnameToIncludeList(ff, 0, "/"); /* include everything */
242 }
243
244 where = argv[1];
245 DoExtract(argv[0]);
246
247 if (bsr) { libbareos::FreeBsr(bsr); }
248 if (prog_name_msg) {
249 Pmsg1(000,
250 _("%d Program Name and/or Program Data Stream records ignored.\n"),
251 prog_name_msg);
252 }
253 if (win32_data_msg) {
254 Pmsg1(000, _("%d Win32 data or Win32 gzip data stream records. Ignored.\n"),
255 win32_data_msg);
256 }
257 TermIncludeExcludeFiles(ff);
258 TermFindFiles(ff);
259 return 0;
260 }
261
262 /*
263 * Cleanup of delayed restore stack with streams for later processing.
264 */
DropDelayedDataStreams()265 static inline void DropDelayedDataStreams()
266 {
267 DelayedDataStream* dds = nullptr;
268
269 if (!delayed_streams || delayed_streams->empty()) { return; }
270
271 foreach_alist (dds, delayed_streams) {
272 free(dds->content);
273 }
274
275 delayed_streams->destroy();
276 }
277
278 /*
279 * Push a data stream onto the delayed restore stack for later processing.
280 */
PushDelayedDataStream(int stream,char * content,uint32_t content_length)281 static inline void PushDelayedDataStream(int stream,
282 char* content,
283 uint32_t content_length)
284 {
285 DelayedDataStream* dds;
286
287 if (!delayed_streams) { delayed_streams = new alist(10, owned_by_alist); }
288
289 dds = (DelayedDataStream*)malloc(sizeof(DelayedDataStream));
290 dds->stream = stream;
291 dds->content = (char*)malloc(content_length);
292 memcpy(dds->content, content, content_length);
293 dds->content_length = content_length;
294
295 delayed_streams->append(dds);
296 }
297
298 /*
299 * Restore any data streams that are restored after the file
300 * is fully restored and has its attributes restored. Things
301 * like acls and xattr are restored after we set the file
302 * attributes otherwise we might clear some security flags
303 * by setting the attributes.
304 */
PopDelayedDataStreams()305 static inline void PopDelayedDataStreams()
306 {
307 DelayedDataStream* dds = nullptr;
308
309 /*
310 * See if there is anything todo.
311 */
312 if (!delayed_streams || delayed_streams->empty()) { return; }
313
314 /*
315 * Only process known delayed data streams here.
316 * If you start using more delayed data streams
317 * be sure to add them in this loop and add the
318 * proper calls here.
319 *
320 * Currently we support delayed data stream
321 * processing for the following type of streams:
322 * - *_ACL_*
323 * - *_XATTR_*
324 */
325 foreach_alist (dds, delayed_streams) {
326 switch (dds->stream) {
327 case STREAM_UNIX_ACCESS_ACL:
328 case STREAM_UNIX_DEFAULT_ACL:
329 case STREAM_ACL_AIX_TEXT:
330 case STREAM_ACL_DARWIN_ACCESS_ACL:
331 case STREAM_ACL_FREEBSD_DEFAULT_ACL:
332 case STREAM_ACL_FREEBSD_ACCESS_ACL:
333 case STREAM_ACL_HPUX_ACL_ENTRY:
334 case STREAM_ACL_IRIX_DEFAULT_ACL:
335 case STREAM_ACL_IRIX_ACCESS_ACL:
336 case STREAM_ACL_LINUX_DEFAULT_ACL:
337 case STREAM_ACL_LINUX_ACCESS_ACL:
338 case STREAM_ACL_TRU64_DEFAULT_ACL:
339 case STREAM_ACL_TRU64_DEFAULT_DIR_ACL:
340 case STREAM_ACL_TRU64_ACCESS_ACL:
341 case STREAM_ACL_SOLARIS_ACLENT:
342 case STREAM_ACL_SOLARIS_ACE:
343 case STREAM_ACL_AFS_TEXT:
344 case STREAM_ACL_AIX_AIXC:
345 case STREAM_ACL_AIX_NFS4:
346 case STREAM_ACL_FREEBSD_NFS4_ACL:
347 case STREAM_ACL_HURD_DEFAULT_ACL:
348 case STREAM_ACL_HURD_ACCESS_ACL:
349 parse_acl_streams(jcr, &acl_data, dds->stream, dds->content,
350 dds->content_length);
351 free(dds->content);
352 break;
353 case STREAM_XATTR_HURD:
354 case STREAM_XATTR_IRIX:
355 case STREAM_XATTR_TRU64:
356 case STREAM_XATTR_AIX:
357 case STREAM_XATTR_OPENBSD:
358 case STREAM_XATTR_SOLARIS_SYS:
359 case STREAM_XATTR_DARWIN:
360 case STREAM_XATTR_FREEBSD:
361 case STREAM_XATTR_LINUX:
362 case STREAM_XATTR_NETBSD:
363 ParseXattrStreams(jcr, &xattr_data, dds->stream, dds->content,
364 dds->content_length);
365 free(dds->content);
366 break;
367 default:
368 Jmsg(jcr, M_WARNING, 0,
369 _("Unknown stream=%d ignored. This shouldn't happen!\n"),
370 dds->stream);
371 break;
372 }
373 }
374
375 /*
376 * We processed the stack so we can destroy it.
377 */
378 delayed_streams->destroy();
379
380 /*
381 * (Re)Initialize the stack for a new use.
382 */
383 delayed_streams->init(10, owned_by_alist);
384
385 return;
386 }
387
ClosePreviousStream(void)388 static void ClosePreviousStream(void)
389 {
390 PopDelayedDataStreams();
391 SetAttributes(jcr, attr, &bfd);
392 }
393
DoExtract(char * devname)394 static void DoExtract(char* devname)
395 {
396 struct stat statp;
397 uint32_t decompress_buf_size;
398
399 EnableBackupPrivileges(NULL, 1);
400
401 dcr = new DeviceControlRecord;
402 jcr = SetupJcr("bextract", devname, bsr, director, dcr, VolumeName,
403 true); /* read device */
404 if (!jcr) { exit(1); }
405 dev = jcr->impl->read_dcr->dev;
406 if (!dev) { exit(1); }
407 dcr = jcr->impl->read_dcr;
408
409 /*
410 * Make sure where directory exists and that it is a directory
411 */
412 if (stat(where, &statp) < 0) {
413 BErrNo be;
414 Emsg2(M_ERROR_TERM, 0, _("Cannot stat %s. It must exist. ERR=%s\n"), where,
415 be.bstrerror());
416 }
417 if (!S_ISDIR(statp.st_mode)) {
418 Emsg1(M_ERROR_TERM, 0, _("%s must be a directory.\n"), where);
419 }
420
421 free(jcr->where);
422 jcr->where = strdup(where);
423 attr = new_attr(jcr);
424
425 jcr->buf_size = DEFAULT_NETWORK_BUFFER_SIZE;
426 SetupDecompressionBuffers(jcr, &decompress_buf_size);
427
428 if (decompress_buf_size > 0) {
429 jcr->compress = CompressionContext{};
430 jcr->compress.inflate_buffer = GetMemory(decompress_buf_size);
431 jcr->compress.inflate_buffer_size = decompress_buf_size;
432 }
433
434 acl_data.last_fname = GetPoolMemory(PM_FNAME);
435 xattr_data.last_fname = GetPoolMemory(PM_FNAME);
436
437 ReadRecords(dcr, RecordCb, MountNextReadVolume);
438
439 /*
440 * If output file is still open, it was the last one in the
441 * archive since we just hit an end of file, so close the file.
442 */
443 if (IsBopen(&bfd)) { ClosePreviousStream(); }
444 FreeAttr(attr);
445
446 FreePoolMemory(acl_data.last_fname);
447 FreePoolMemory(xattr_data.last_fname);
448
449 if (delayed_streams) {
450 DropDelayedDataStreams();
451 delete delayed_streams;
452 }
453
454 CleanupCompression(jcr);
455
456 CleanDevice(jcr->impl->dcr);
457 dev->term();
458 FreeDeviceControlRecord(dcr);
459 FreeJcr(jcr);
460
461 printf(_("%u files restored.\n"), num_files);
462
463 return;
464 }
465
StoreData(BareosWinFilePacket * bfd,char * data,const int32_t length)466 static bool StoreData(BareosWinFilePacket* bfd,
467 char* data,
468 const int32_t length)
469 {
470 if (is_win32_stream(attr->data_stream) && !have_win32_api()) {
471 SetPortableBackup(bfd);
472 if (!processWin32BackupAPIBlock(bfd, data, length)) {
473 BErrNo be;
474 Emsg2(M_ERROR_TERM, 0, _("Write error on %s: %s\n"), attr->ofname,
475 be.bstrerror());
476 return false;
477 }
478 } else if (bwrite(bfd, data, length) != (ssize_t)length) {
479 BErrNo be;
480 Emsg2(M_ERROR_TERM, 0, _("Write error on %s: %s\n"), attr->ofname,
481 be.bstrerror());
482 return false;
483 }
484
485 return true;
486 }
487
488 /*
489 * Called here for each record from ReadRecords()
490 */
RecordCb(DeviceControlRecord * dcr,DeviceRecord * rec)491 static bool RecordCb(DeviceControlRecord* dcr, DeviceRecord* rec)
492 {
493 int status;
494 JobControlRecord* jcr = dcr->jcr;
495
496 if (rec->FileIndex < 0) { return true; /* we don't want labels */ }
497
498 /* File Attributes stream */
499
500 switch (rec->maskedStream) {
501 case STREAM_UNIX_ATTRIBUTES:
502 case STREAM_UNIX_ATTRIBUTES_EX:
503
504 /* If extracting, it was from previous stream, so
505 * close the output file.
506 */
507 if (extract) {
508 if (!IsBopen(&bfd)) {
509 Emsg0(M_ERROR, 0,
510 _("Logic error output file should be open but is not.\n"));
511 }
512 ClosePreviousStream();
513 extract = false;
514 }
515
516 if (!UnpackAttributesRecord(jcr, rec->Stream, rec->data, rec->data_len,
517 attr)) {
518 Emsg0(M_ERROR_TERM, 0, _("Cannot continue.\n"));
519 }
520
521 if (FileIsIncluded(ff, attr->fname) && !FileIsExcluded(ff, attr->fname)) {
522 attr->data_stream = DecodeStat(attr->attr, &attr->statp,
523 sizeof(attr->statp), &attr->LinkFI);
524 if (!IsRestoreStreamSupported(attr->data_stream)) {
525 if (!non_support_data++) {
526 Jmsg(jcr, M_ERROR, 0,
527 _("%s stream not supported on this Client.\n"),
528 stream_to_ascii(attr->data_stream));
529 }
530 extract = false;
531 return true;
532 }
533
534 BuildAttrOutputFnames(jcr, attr);
535
536 if (attr->type ==
537 FT_DELETED) { /* TODO: choose the right fname/ofname */
538 Jmsg(jcr, M_INFO, 0, _("%s was deleted.\n"), attr->fname);
539 extract = false;
540 return true;
541 }
542
543 extract = false;
544 status = CreateFile(jcr, attr, &bfd, REPLACE_ALWAYS);
545 switch (status) {
546 case CF_ERROR:
547 case CF_SKIP:
548 break;
549 case CF_EXTRACT:
550 extract = true;
551 PrintLsOutput(jcr, attr);
552 num_files++;
553 fileAddr = 0;
554 break;
555 case CF_CREATED:
556 ClosePreviousStream();
557 PrintLsOutput(jcr, attr);
558 num_files++;
559 fileAddr = 0;
560 break;
561 }
562 }
563 break;
564
565 case STREAM_RESTORE_OBJECT:
566 /* nothing to do */
567 break;
568
569 /* Data stream and extracting */
570 case STREAM_FILE_DATA:
571 case STREAM_SPARSE_DATA:
572 case STREAM_WIN32_DATA:
573
574 if (extract) {
575 if (rec->maskedStream == STREAM_SPARSE_DATA) {
576 ser_declare;
577 uint64_t faddr;
578 wbuf = rec->data + OFFSET_FADDR_SIZE;
579 wsize = rec->data_len - OFFSET_FADDR_SIZE;
580 SerBegin(rec->data, OFFSET_FADDR_SIZE);
581 unser_uint64(faddr);
582 if (fileAddr != faddr) {
583 fileAddr = faddr;
584 if (blseek(&bfd, (boffset_t)fileAddr, SEEK_SET) < 0) {
585 BErrNo be;
586 Emsg2(M_ERROR_TERM, 0, _("Seek error on %s: %s\n"), attr->ofname,
587 be.bstrerror());
588 }
589 }
590 } else {
591 wbuf = rec->data;
592 wsize = rec->data_len;
593 }
594 total += wsize;
595 Dmsg2(8, "Write %u bytes, total=%u\n", wsize, total);
596 StoreData(&bfd, wbuf, wsize);
597 fileAddr += wsize;
598 }
599 break;
600
601 /* GZIP data stream and Compressed data stream */
602 case STREAM_GZIP_DATA:
603 case STREAM_SPARSE_GZIP_DATA:
604 case STREAM_COMPRESSED_DATA:
605 case STREAM_SPARSE_COMPRESSED_DATA:
606 case STREAM_WIN32_COMPRESSED_DATA:
607 if (extract) {
608 if (rec->maskedStream == STREAM_SPARSE_GZIP_DATA ||
609 rec->maskedStream == STREAM_SPARSE_COMPRESSED_DATA) {
610 ser_declare;
611 uint64_t faddr;
612 char ec1[50];
613
614 wbuf = rec->data + OFFSET_FADDR_SIZE;
615 wsize = rec->data_len - OFFSET_FADDR_SIZE;
616
617 SerBegin(rec->data, OFFSET_FADDR_SIZE);
618 unser_uint64(faddr);
619 SerEnd(rec->data, OFFSET_FADDR_SIZE);
620
621 if (fileAddr != faddr) {
622 fileAddr = faddr;
623 if (blseek(&bfd, (boffset_t)fileAddr, SEEK_SET) < 0) {
624 BErrNo be;
625
626 Emsg3(M_ERROR, 0, _("Seek to %s error on %s: ERR=%s\n"),
627 edit_uint64(fileAddr, ec1), attr->ofname, be.bstrerror());
628 extract = false;
629 return true;
630 }
631 }
632 } else {
633 wbuf = rec->data;
634 wsize = rec->data_len;
635 }
636
637 if (DecompressData(jcr, attr->ofname, rec->maskedStream, &wbuf, &wsize,
638 false)) {
639 Dmsg2(100, "Write uncompressed %d bytes, total before write=%d\n",
640 wsize, total);
641 StoreData(&bfd, wbuf, wsize);
642 total += wsize;
643 fileAddr += wsize;
644 Dmsg2(100, "Compress len=%d uncompressed=%d\n", rec->data_len, wsize);
645 } else {
646 extract = false;
647 return false;
648 }
649 }
650 break;
651
652 case STREAM_MD5_DIGEST:
653 case STREAM_SHA1_DIGEST:
654 case STREAM_SHA256_DIGEST:
655 case STREAM_SHA512_DIGEST:
656 break;
657
658 case STREAM_SIGNED_DIGEST:
659 case STREAM_ENCRYPTED_SESSION_DATA:
660 // TODO landonf: Investigate crypto support in the storage daemon
661 break;
662
663 case STREAM_PROGRAM_NAMES:
664 case STREAM_PROGRAM_DATA:
665 if (!prog_name_msg) {
666 Pmsg0(000, _("Got Program Name or Data Stream. Ignored.\n"));
667 prog_name_msg++;
668 }
669 break;
670
671 case STREAM_UNIX_ACCESS_ACL: /* Deprecated Standard ACL attributes on UNIX
672 */
673 case STREAM_UNIX_DEFAULT_ACL: /* Deprecated Default ACL attributes on UNIX
674 */
675 case STREAM_ACL_AIX_TEXT:
676 case STREAM_ACL_DARWIN_ACCESS_ACL:
677 case STREAM_ACL_FREEBSD_DEFAULT_ACL:
678 case STREAM_ACL_FREEBSD_ACCESS_ACL:
679 case STREAM_ACL_HPUX_ACL_ENTRY:
680 case STREAM_ACL_IRIX_DEFAULT_ACL:
681 case STREAM_ACL_IRIX_ACCESS_ACL:
682 case STREAM_ACL_LINUX_DEFAULT_ACL:
683 case STREAM_ACL_LINUX_ACCESS_ACL:
684 case STREAM_ACL_TRU64_DEFAULT_ACL:
685 case STREAM_ACL_TRU64_DEFAULT_DIR_ACL:
686 case STREAM_ACL_TRU64_ACCESS_ACL:
687 case STREAM_ACL_SOLARIS_ACLENT:
688 case STREAM_ACL_SOLARIS_ACE:
689 case STREAM_ACL_AFS_TEXT:
690 case STREAM_ACL_AIX_AIXC:
691 case STREAM_ACL_AIX_NFS4:
692 case STREAM_ACL_FREEBSD_NFS4_ACL:
693 case STREAM_ACL_HURD_DEFAULT_ACL:
694 case STREAM_ACL_HURD_ACCESS_ACL:
695 if (extract) {
696 PmStrcpy(acl_data.last_fname, attr->fname);
697 PushDelayedDataStream(rec->maskedStream, rec->data, rec->data_len);
698 }
699 break;
700
701 case STREAM_XATTR_HURD:
702 case STREAM_XATTR_IRIX:
703 case STREAM_XATTR_TRU64:
704 case STREAM_XATTR_AIX:
705 case STREAM_XATTR_OPENBSD:
706 case STREAM_XATTR_SOLARIS_SYS:
707 case STREAM_XATTR_SOLARIS:
708 case STREAM_XATTR_DARWIN:
709 case STREAM_XATTR_FREEBSD:
710 case STREAM_XATTR_LINUX:
711 case STREAM_XATTR_NETBSD:
712 if (extract) {
713 PmStrcpy(xattr_data.last_fname, attr->fname);
714 PushDelayedDataStream(rec->maskedStream, rec->data, rec->data_len);
715 }
716 break;
717
718 case STREAM_NDMP_SEPARATOR:
719 break;
720
721 default:
722 /*
723 * If extracting, weird stream (not 1 or 2), close output file anyway
724 */
725 if (extract) {
726 if (!IsBopen(&bfd)) {
727 Emsg0(M_ERROR, 0,
728 _("Logic error output file should be open but is not.\n"));
729 }
730 ClosePreviousStream();
731 extract = false;
732 }
733 Jmsg(jcr, M_ERROR, 0,
734 _("Unknown stream=%d ignored. This shouldn't happen!\n"),
735 rec->Stream);
736 break;
737
738 } /* end switch */
739 return true;
740 }
741