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