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