]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/filed/acl.c
Don't copy xattr and acl streams.
[bacula/bacula] / bacula / src / filed / acl.c
1 /*
2    Bacula® - The Network Backup Solution
3
4    Copyright (C) 2004-2012 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  * Functions to handle ACLs for bacula.
30  *
31  * Currently we support the following OSes:
32  *   - AIX (pre-5.3 and post 5.3 acls, acl_get and aclx_get interface)
33  *   - Darwin
34  *   - FreeBSD (POSIX and NFSv4/ZFS acls)
35  *   - HPUX
36  *   - IRIX
37  *   - Linux
38  *   - Solaris (POSIX and NFSv4/ZFS acls)
39  *   - Tru64
40  *
41  * We handle two different types of ACLs: access and default ACLS.
42  * On most systems that support default ACLs they only apply to directories.
43  *
44  * On some systems (eg. linux and FreeBSD) we must obtain the two ACLs
45  * independently, while others (eg. Solaris) provide both in one call.
46  *
47  * The Filed saves ACLs in their native format and uses different streams
48  * for all different platforms. Currently we only allow ACLs to be restored
49  * which were saved in the native format of the platform they are extracted
50  * on. Later on we might add conversion functions for mapping from one
51  * platform to an other or allow restores of systems that use the same
52  * native format.
53  *
54  * Its also interesting to see what the exact format of acl text is on
55  * certain platforms and if they use they same encoding we might allow
56  * different platform streams to be decoded on an other similar platform.
57  *
58  *   Original written by Preben 'Peppe' Guldberg, December 2004
59  *   Major rewrite by Marco van Wieringen, November 2008
60  *   Major overhaul by Marco van Wieringen, January 2012
61  */
62   
63 #include "bacula.h"
64 #include "filed.h"
65   
66 #if !defined(HAVE_ACL)
67 /**
68  * Entry points when compiled without support for ACLs or on an unsupported platform.
69  */
70 bacl_exit_code build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
71 {
72    return bacl_exit_fatal;
73 }
74
75 bacl_exit_code parse_acl_streams(JCR *jcr,
76                                  int stream,
77                                  char *content,
78                                  uint32_t content_length)
79 {
80    return bacl_exit_fatal;
81 }
82 #else
83 /**
84  * Send an ACL stream to the SD.
85  */
86 static bacl_exit_code send_acl_stream(JCR *jcr, int stream)
87 {
88    BSOCK *sd = jcr->store_bsock;
89    POOLMEM *msgsave;
90 #ifdef FD_NO_SEND_TEST
91    return bacl_exit_ok;
92 #endif
93
94    /*
95     * Sanity check
96     */
97    if (jcr->acl_data->u.build->content_length <= 0) {
98       return bacl_exit_ok;
99    }
100
101    /*
102     * Send header
103     */
104    if (!sd->fsend("%ld %d 0", jcr->JobFiles, stream)) {
105       Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
106             sd->bstrerror());
107       return bacl_exit_fatal;
108    }
109
110    /*
111     * Send the buffer to the storage deamon
112     */
113    Dmsg1(400, "Backing up ACL <%s>\n", jcr->acl_data->u.build->content);
114    msgsave = sd->msg;
115    sd->msg = jcr->acl_data->u.build->content;
116    sd->msglen = jcr->acl_data->u.build->content_length + 1;
117    if (!sd->send()) {
118       sd->msg = msgsave;
119       sd->msglen = 0;
120       Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
121             sd->bstrerror());
122       return bacl_exit_fatal;
123    }
124
125    jcr->JobBytes += sd->msglen;
126    sd->msg = msgsave;
127    if (!sd->signal(BNET_EOD)) {
128       Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
129             sd->bstrerror());
130       return bacl_exit_fatal;
131    }
132
133    Dmsg1(200, "ACL of file: %s successfully backed up!\n", jcr->last_fname);
134    return bacl_exit_ok;
135 }
136
137 /*
138  * First the native ACLs.
139  */
140 #if defined(HAVE_ACL)
141 #if defined(HAVE_AIX_OS)
142
143 #if defined(HAVE_EXTENDED_ACL)
144
145 #include <sys/access.h>
146 #include <sys/acl.h>
147
148 static bool acl_is_trivial(struct acl *acl)
149 {
150    return (acl_last(acl) != acl->acl_ext ? false : true);
151 }
152
153 static bool acl_nfs4_is_trivial(nfs4_acl_int_t *acl)
154 {
155    return (acl->aclEntryN > 0 ? false : true);
156 }
157
158 /*
159  * Define the supported ACL streams for this OS
160  */
161 static int os_access_acl_streams[3] = {
162    STREAM_ACL_AIX_TEXT,
163    STREAM_ACL_AIX_AIXC,
164    STREAM_ACL_AIX_NFS4
165 };
166 static int os_default_acl_streams[1] = {
167    -1
168 };
169
170 static bacl_exit_code aix_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
171 {
172    berrno be;
173    mode_t mode;
174    acl_type_t type;
175    size_t aclsize, acltxtsize;
176    bacl_exit_code retval = bacl_exit_error;
177    POOLMEM *aclbuf = get_pool_memory(PM_MESSAGE);
178
179    /*
180     * First see how big the buffers should be.
181     */
182    type.u64 = ACL_ANY;
183    if (aclx_get(jcr->last_fname, GET_ACLINFO_ONLY, &type, NULL, &aclsize, NULL) < 0) {
184       switch (errno) {
185       case ENOENT:
186          retval = bacl_exit_ok;
187          goto bail_out;
188       default:
189          Mmsg2(jcr->errmsg,
190                _("aclx_get error on file \"%s\": ERR=%s\n"),
191                jcr->last_fname, be.bstrerror());
192          Dmsg2(100, "aclx_get error file=%s ERR=%s\n",
193                jcr->last_fname, be.bstrerror());
194          goto bail_out;
195       }
196    }
197
198    /*
199     * Make sure the buffers are big enough.
200     */
201    aclbuf = check_pool_memory_size(aclbuf, aclsize + 1);
202
203    /*
204     * Retrieve the ACL info.
205     */
206    if (aclx_get(jcr->last_fname, 0, &type, aclbuf, &aclsize, &mode) < 0) {
207       switch (errno) {
208       case ENOENT:
209          retval = bacl_exit_ok;
210          goto bail_out;
211       default:
212          Mmsg2(jcr->errmsg,
213                _("aclx_get error on file \"%s\": ERR=%s\n"),
214                jcr->last_fname, be.bstrerror());
215          Dmsg2(100, "aclx_get error file=%s ERR=%s\n",
216                jcr->last_fname, be.bstrerror());
217          goto bail_out;
218       }
219    }
220
221    /*
222     * See if the acl is non trivial.
223     */
224    switch (type.u64) {
225    case ACL_AIXC:
226       if (acl_is_trivial((struct acl *)aclbuf)) {
227          retval = bacl_exit_ok;
228          goto bail_out;
229       }
230       break;
231    case ACL_NFS4:
232       if (acl_nfs4_is_trivial((nfs4_acl_int_t *)aclbuf)) {
233          retval = bacl_exit_ok;
234          goto bail_out;
235       }
236       break;
237    default:
238       Mmsg2(jcr->errmsg,
239             _("Unknown acl type encountered on file \"%s\": %ld\n"),
240             jcr->last_fname, type.u64);
241       Dmsg2(100, "Unknown acl type encountered on file \"%s\": %ld\n",
242             jcr->last_fname, type.u64);
243       goto bail_out;
244    }
245
246    /*
247     * We have a non-trivial acl lets convert it into some ASCII form.
248     */
249    acltxtsize = sizeof_pool_memory(jcr->acl_data->u.build->content);
250    if (aclx_printStr(jcr->acl_data->u.build->content, &acltxtsize, aclbuf,
251                      aclsize, type, jcr->last_fname, 0) < 0) {
252       switch (errno) {
253       case ENOSPC:
254          /*
255           * Our buffer is not big enough, acltxtsize should be updated with the value
256           * the aclx_printStr really need. So we increase the buffer and try again.
257           */
258          jcr->acl_data->u.build->content =
259          check_pool_memory_size(jcr->acl_data->u.build->content, acltxtsize + 1);
260          if (aclx_printStr(jcr->acl_data->u.build->content, &acltxtsize, aclbuf,
261                            aclsize, type, jcr->last_fname, 0) < 0) {
262             Mmsg1(jcr->errmsg,
263                   _("Failed to convert acl into text on file \"%s\"\n"),
264                   jcr->last_fname);
265             Dmsg2(100, "Failed to convert acl into text on file \"%s\": %ld\n",
266                   jcr->last_fname, type.u64);
267             goto bail_out;
268          }
269          break;
270       default:
271          Mmsg1(jcr->errmsg,
272                _("Failed to convert acl into text on file \"%s\"\n"),
273                jcr->last_fname);
274          Dmsg2(100, "Failed to convert acl into text on file \"%s\": %ld\n",
275                jcr->last_fname, type.u64);
276          goto bail_out;
277       }
278    }
279
280    jcr->acl_data->u.build->u.build->content_length = strlen(jcr->acl_data->u.build->content) + 1;
281    switch (type.u64) {
282    case ACL_AIXC:
283       retval = send_acl_stream(jcr, STREAM_ACL_AIX_AIXC);
284    case ACL_NFS4:
285       retval = send_acl_stream(jcr, STREAM_ACL_AIX_NFS4);
286    }
287
288 bail_out:
289    free_pool_memory(aclbuf);
290
291    return retval;
292 }
293
294 static bacl_exit_code aix_parse_acl_streams(JCR *jcr,
295                                             int stream,
296                                             char *content,
297                                             uint32_t content_length)
298 {
299    int cnt;
300    berrno be;
301    acl_type_t type;
302    size_t aclsize;
303    bacl_exit_code retval = bacl_exit_error;
304    POOLMEM *aclbuf = get_pool_memory(PM_MESSAGE);
305
306    switch (stream) {
307    case STREAM_ACL_AIX_TEXT:
308       /*
309        * Handle the old stream using the old system call for now.
310        */
311       if (acl_put(jcr->last_fname, content, 0) != 0) {
312          retval = bacl_exit_error;
313          goto bail_out;
314       }
315       retval = bacl_exit_ok;
316       goto bail_out;
317    case STREAM_ACL_AIX_AIXC:
318       type.u64 = ACL_AIXC;
319       break;
320    case STREAM_ACL_AIX_NFS4:
321       type.u64 = ACL_NFS4;
322       break;
323    default:
324       goto bail_out;
325    } /* end switch (stream) */
326
327    /*
328     * Set the acl buffer to an initial size. For now we set it
329     * to the same size as the ASCII representation.
330     */
331    aclbuf = check_pool_memory_size(aclbuf, content_length);
332    aclsize = content_length;
333    if (aclx_scanStr(content, aclbuf, &aclsize, type) < 0) {
334       switch (errno) {
335       case ENOSPC:
336          /*
337           * The buffer isn't big enough. The man page doesn't say that aclsize
338           * is updated to the needed size as what is done with aclx_printStr.
339           * So for now we try to increase the buffer a maximum of 3 times
340           * and retry the conversion.
341           */
342          for (cnt = 0; cnt < 3; cnt++) {
343             aclsize = 2 * aclsize;
344             aclbuf = check_pool_memory_size(aclbuf, aclsize);
345
346             if (aclx_scanStr(content, aclbuf, &aclsize, type) == 0) {
347                break;
348             }
349
350             /*
351              * See why we failed this time, ENOSPC retry if max retries not met,
352              * otherwise abort.
353              */
354             switch (errno) {
355             case ENOSPC:
356                if (cnt < 3) {
357                   continue;
358                }
359                /* FALL THROUGH */
360             default:
361                Mmsg2(jcr->errmsg,
362                      _("aclx_scanStr error on file \"%s\": ERR=%s\n"),
363                      jcr->last_fname, be.bstrerror());
364                Dmsg2(100, "aclx_scanStr error file=%s ERR=%s\n",
365                      jcr->last_fname, be.bstrerror());
366                goto bail_out;
367             }
368          }
369          break;
370       default:
371          Mmsg2(jcr->errmsg,
372                _("aclx_scanStr error on file \"%s\": ERR=%s\n"),
373                jcr->last_fname, be.bstrerror());
374          Dmsg2(100, "aclx_scanStr error file=%s ERR=%s\n",
375                jcr->last_fname, be.bstrerror());
376       }
377    }
378
379    if (aclx_put(jcr->last_fname, SET_ACL, type, aclbuf, aclsize, 0) < 0) {
380       switch (errno) {
381       case ENOENT:
382          retval = bacl_exit_ok;
383          goto bail_out;
384       default:
385          Mmsg2(jcr->errmsg,
386                _("aclx_put error on file \"%s\": ERR=%s\n"),
387                jcr->last_fname, be.bstrerror());
388          Dmsg2(100, "aclx_put error file=%s ERR=%s\n",
389                jcr->last_fname, be.bstrerror());
390          goto bail_out;
391       }
392    }
393
394    retval = bacl_exit_ok;
395
396 bail_out:
397    free_pool_memory(aclbuf);
398
399    return retval;
400 }
401
402 #else /* HAVE_EXTENDED_ACL */
403
404 #include <sys/access.h>
405
406 /*
407  * Define the supported ACL streams for this OS
408  */
409 static int os_access_acl_streams[1] = {
410    STREAM_ACL_AIX_TEXT
411 };
412 static int os_default_acl_streams[1] = {
413    -1
414 };
415
416 static bacl_exit_code aix_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
417 {
418    char *acl_text;
419
420    if ((acl_text = acl_get(jcr->last_fname)) != NULL) {
421       jcr->acl_data->u.build->content_length =
422       pm_strcpy(jcr->acl_data->u.build->content, acl_text);
423       actuallyfree(acl_text);
424       return send_acl_stream(jcr, STREAM_ACL_AIX_TEXT);
425    }
426    return bacl_exit_error;
427 }
428
429 static bacl_exit_code aix_parse_acl_streams(JCR *jcr,
430                                             int stream,
431                                             char *content,
432                                             uint32_t content_length)
433 {
434    if (acl_put(jcr->last_fname, content, 0) != 0) {
435       return bacl_exit_error;
436    }
437    return bacl_exit_ok;
438 }
439 #endif /* HAVE_EXTENDED_ACL */
440
441 /*
442  * For this OS setup the build and parse function pointer to the OS specific functions.
443  */
444 static bacl_exit_code (*os_build_acl_streams)
445                       (JCR *jcr, FF_PKT *ff_pkt) =
446                       aix_build_acl_streams;
447 static bacl_exit_code (*os_parse_acl_streams)
448                       (JCR *jcr, int stream, char *content, uint32_t content_length) =
449                       aix_parse_acl_streams;
450
451 #elif defined(HAVE_DARWIN_OS) || \
452       defined(HAVE_FREEBSD_OS) || \
453       defined(HAVE_IRIX_OS) || \
454       defined(HAVE_OSF1_OS) || \
455       defined(HAVE_LINUX_OS)
456
457 #include <sys/types.h>
458
459 #ifdef HAVE_SYS_ACL_H
460 #include <sys/acl.h>
461 #else
462 #error "configure failed to detect availability of sys/acl.h"
463 #endif
464
465 /*
466  * On IRIX we can get shortened ACLs
467  */
468 #if defined(HAVE_IRIX_OS) && defined(BACL_WANT_SHORT_ACLS)
469 #define acl_to_text(acl,len)     acl_to_short_text((acl), (len))
470 #endif
471
472 /*
473  * On Linux we can get numeric and/or shorted ACLs
474  */
475 #if defined(HAVE_LINUX_OS)
476 #if defined(BACL_WANT_SHORT_ACLS) && defined(BACL_WANT_NUMERIC_IDS)
477 #define BACL_ALTERNATE_TEXT            (TEXT_ABBREVIATE|TEXT_NUMERIC_IDS)
478 #elif defined(BACL_WANT_SHORT_ACLS)
479 #define BACL_ALTERNATE_TEXT            TEXT_ABBREVIATE
480 #elif defined(BACL_WANT_NUMERIC_IDS)
481 #define BACL_ALTERNATE_TEXT            TEXT_NUMERIC_IDS
482 #endif
483 #ifdef BACL_ALTERNATE_TEXT
484 #include <acl/libacl.h>
485 #define acl_to_text(acl,len)     (acl_to_any_text((acl), NULL, ',', BACL_ALTERNATE_TEXT))
486 #endif
487 #endif
488
489 /*
490  * On FreeBSD we can get numeric ACLs
491  */
492 #if defined(HAVE_FREEBSD_OS)
493 #if defined(BACL_WANT_NUMERIC_IDS)
494 #define BACL_ALTERNATE_TEXT            ACL_TEXT_NUMERIC_IDS
495 #endif
496 #ifdef BACL_ALTERNATE_TEXT
497 #define acl_to_text(acl,len)     (acl_to_text_np((acl), (len), BACL_ALTERNATE_TEXT))
498 #endif
499 #endif
500
501 /*
502  * Some generic functions used by multiple OSes.
503  */
504 static acl_type_t bac_to_os_acltype(bacl_type acltype)
505 {
506    acl_type_t ostype;
507
508    switch (acltype) {
509    case BACL_TYPE_ACCESS:
510       ostype = ACL_TYPE_ACCESS;
511       break;
512    case BACL_TYPE_DEFAULT:
513       ostype = ACL_TYPE_DEFAULT;
514       break;
515 #ifdef HAVE_ACL_TYPE_NFS4
516       /*
517        * FreeBSD has an additional acl type named ACL_TYPE_NFS4.
518        */
519    case BACL_TYPE_NFS4:
520       ostype = ACL_TYPE_NFS4;
521       break;
522 #endif
523 #ifdef HAVE_ACL_TYPE_DEFAULT_DIR
524    case BACL_TYPE_DEFAULT_DIR:
525       /*
526        * TRU64 has an additional acl type named ACL_TYPE_DEFAULT_DIR.
527        */
528       ostype = ACL_TYPE_DEFAULT_DIR;
529       break;
530 #endif
531 #ifdef HAVE_ACL_TYPE_EXTENDED
532    case BACL_TYPE_EXTENDED:
533       /*
534        * MacOSX has an additional acl type named ACL_TYPE_EXTENDED.
535        */
536       ostype = ACL_TYPE_EXTENDED;
537       break;
538 #endif
539    default:
540       /*
541        * This should never happen, as the per OS version function only tries acl
542        * types supported on a certain platform.
543        */
544       ostype = (acl_type_t)ACL_TYPE_NONE;
545       break;
546    }
547    return ostype;
548 }
549
550 static int acl_count_entries(acl_t acl)
551 {
552    int count = 0;
553 #if defined(HAVE_FREEBSD_OS) || \
554     defined(HAVE_LINUX_OS)
555    acl_entry_t ace;
556    int entry_available;
557
558    entry_available = acl_get_entry(acl, ACL_FIRST_ENTRY, &ace);
559    while (entry_available == 1) {
560       count++;
561       entry_available = acl_get_entry(acl, ACL_NEXT_ENTRY, &ace);
562    }
563 #elif defined(HAVE_IRIX_OS)
564    count = acl->acl_cnt;
565 #elif defined(HAVE_OSF1_OS)
566    count = acl->acl_num;
567 #elif defined(HAVE_DARWIN_OS)
568    acl_entry_t ace;
569    int entry_available;
570
571    entry_available = acl_get_entry(acl, ACL_FIRST_ENTRY, &ace);
572    while (entry_available == 0) {
573       count++;
574       entry_available = acl_get_entry(acl, ACL_NEXT_ENTRY, &ace);
575    }
576 #endif
577    return count;
578 }
579
580 #if !defined(HAVE_DARWIN_OS)
581 /*
582  * See if an acl is a trivial one (e.g. just the stat bits encoded as acl.)
583  * There is no need to store those acls as we already store the stat bits too.
584  */
585 static bool acl_is_trivial(acl_t acl)
586 {
587   /*
588    * acl is trivial if it has only the following entries:
589    * "user::",
590    * "group::",
591    * "other::"
592    */
593    acl_entry_t ace;
594    acl_tag_t tag;
595 #if defined(HAVE_FREEBSD_OS) || \
596     defined(HAVE_LINUX_OS)
597    int entry_available;
598
599    entry_available = acl_get_entry(acl, ACL_FIRST_ENTRY, &ace);
600    while (entry_available == 1) {
601       /*
602        * Get the tag type of this acl entry.
603        * If we fail to get the tagtype we call the acl non-trivial.
604        */
605       if (acl_get_tag_type(ace, &tag) < 0)
606          return true;
607       /*
608        * Anything other the ACL_USER_OBJ, ACL_GROUP_OBJ or ACL_OTHER breaks the spell.
609        */
610       if (tag != ACL_USER_OBJ &&
611           tag != ACL_GROUP_OBJ &&
612           tag != ACL_OTHER)
613          return false;
614       entry_available = acl_get_entry(acl, ACL_NEXT_ENTRY, &ace);
615    }
616    return true;
617 #elif defined(HAVE_IRIX_OS)
618    int n;
619
620    for (n = 0; n < acl->acl_cnt; n++) {
621       ace = &acl->acl_entry[n];
622       tag = ace->ae_tag;
623
624       /*
625        * Anything other the ACL_USER_OBJ, ACL_GROUP_OBJ or ACL_OTHER breaks the spell.
626        */
627       if (tag != ACL_USER_OBJ &&
628           tag != ACL_GROUP_OBJ &&
629           tag != ACL_OTHER_OBJ)
630          return false;
631    }
632    return true;
633 #elif defined(HAVE_OSF1_OS)
634    int count;
635
636    ace = acl->acl_first;
637    count = acl->acl_num;
638
639    while (count > 0) {
640       tag = ace->entry->acl_type;
641       /*
642        * Anything other the ACL_USER_OBJ, ACL_GROUP_OBJ or ACL_OTHER breaks the spell.
643        */
644       if (tag != ACL_USER_OBJ &&
645           tag != ACL_GROUP_OBJ &&
646           tag != ACL_OTHER)
647          return false;
648       /*
649        * On Tru64, perm can also contain non-standard bits such as
650        * PERM_INSERT, PERM_DELETE, PERM_MODIFY, PERM_LOOKUP, ...
651        */
652       if ((ace->entry->acl_perm & ~(ACL_READ | ACL_WRITE | ACL_EXECUTE)))
653          return false;
654       ace = ace->next;
655       count--;
656    }
657    return true;
658 #endif
659 }
660 #endif
661
662 /**
663  * Generic wrapper around acl_get_file call.
664  */
665 static bacl_exit_code generic_get_acl_from_os(JCR *jcr, bacl_type acltype)
666 {
667    acl_t acl;
668    acl_type_t ostype;
669    char *acl_text;
670    berrno be;
671    bacl_exit_code retval = bacl_exit_ok;
672
673    ostype = bac_to_os_acltype(acltype);
674    acl = acl_get_file(jcr->last_fname, ostype);
675    if (acl) {
676       /**
677        * From observation, IRIX's acl_get_file() seems to return a
678        * non-NULL acl with a count field of -1 when a file has no ACL
679        * defined, while IRIX's acl_to_text() returns NULL when presented
680        * with such an ACL. 
681        *
682        * For all other implmentations we check if there are more then
683        * zero entries in the acl returned.
684        */
685       if (acl_count_entries(acl) <= 0) {
686          goto bail_out;
687       }
688
689       /*
690        * Make sure this is not just a trivial ACL.
691        */
692 #if !defined(HAVE_DARWIN_OS)
693       if (acltype == BACL_TYPE_ACCESS && acl_is_trivial(acl)) {
694          /*
695           * The ACLs simply reflect the (already known) standard permissions
696           * So we don't send an ACL stream to the SD.
697           */
698          goto bail_out;
699       }
700 #endif
701 #if defined(HAVE_FREEBSD_OS) && defined(_PC_ACL_NFS4)
702       if (acltype == BACL_TYPE_NFS4) {
703          int trivial;
704          if (acl_is_trivial_np(acl, &trivial) == 0) {
705             if (trivial == 1) {
706                /*
707                 * The ACLs simply reflect the (already known) standard permissions
708                 * So we don't send an ACL stream to the SD.
709                 */
710                goto bail_out;
711             }
712          }
713       }
714 #endif
715
716       /*
717        * Convert the internal acl representation into a text representation.
718        */
719       if ((acl_text = acl_to_text(acl, NULL)) != NULL) {
720          jcr->acl_data->u.build->content_length =
721          pm_strcpy(jcr->acl_data->u.build->content, acl_text);
722          acl_free(acl);
723          acl_free(acl_text);
724          return bacl_exit_ok;
725       }
726
727       Mmsg2(jcr->errmsg,
728             _("acl_to_text error on file \"%s\": ERR=%s\n"),
729             jcr->last_fname, be.bstrerror());
730       Dmsg2(100, "acl_to_text error file=%s ERR=%s\n",  
731             jcr->last_fname, be.bstrerror());
732
733       retval = bacl_exit_error;
734       goto bail_out;
735    } else {
736       /*
737        * Handle errors gracefully.
738        */
739       switch (errno) {
740 #if defined(BACL_ENOTSUP)
741       case BACL_ENOTSUP:
742          /*
743           * If the filesystem reports it doesn't support ACLs we clear the
744           * BACL_FLAG_SAVE_NATIVE flag so we skip ACL saves on all other files
745           * on the same filesystem. The BACL_FLAG_SAVE_NATIVE flag gets set again
746           * when we change from one filesystem to an other.
747           */
748          jcr->acl_data->flags &= ~BACL_FLAG_SAVE_NATIVE;
749          goto bail_out;
750 #endif
751       case ENOENT:
752          goto bail_out;
753       default:
754          /* Some real error */
755          Mmsg2(jcr->errmsg,
756                _("acl_get_file error on file \"%s\": ERR=%s\n"),
757                jcr->last_fname, be.bstrerror());
758          Dmsg2(100, "acl_get_file error file=%s ERR=%s\n",  
759                jcr->last_fname, be.bstrerror());
760
761          retval = bacl_exit_error;
762          goto bail_out;
763       }
764    }
765
766 bail_out:
767    if (acl) {
768       acl_free(acl);
769    }
770    pm_strcpy(jcr->acl_data->u.build->content, "");
771    jcr->acl_data->u.build->content_length = 0;
772    return retval;
773 }
774
775 /**
776  * Generic wrapper around acl_set_file call.
777  */
778 static bacl_exit_code generic_set_acl_on_os(JCR *jcr,
779                                             bacl_type acltype,
780                                             char *content,
781                                             uint32_t content_length)
782 {
783    acl_t acl;
784    acl_type_t ostype;
785    berrno be;
786
787    /*
788     * If we get empty default ACLs, clear ACLs now
789     */
790    ostype = bac_to_os_acltype(acltype);
791    if (ostype == ACL_TYPE_DEFAULT && strlen(content) == 0) {
792       if (acl_delete_def_file(jcr->last_fname) == 0) {
793          return bacl_exit_ok;
794       }
795       switch (errno) {
796       case ENOENT:
797          return bacl_exit_ok;
798 #if defined(BACL_ENOTSUP)
799       case BACL_ENOTSUP:
800          /*
801           * If the filesystem reports it doesn't support ACLs we clear the
802           * BACL_FLAG_RESTORE_NATIVE flag so we skip ACL restores on all other files
803           * on the same filesystem. The BACL_FLAG_RESTORE_NATIVE flag gets set again
804           * when we change from one filesystem to an other.
805           */
806          jcr->acl_data->flags &= ~BACL_FLAG_RESTORE_NATIVE;
807          Mmsg1(jcr->errmsg,
808                _("acl_delete_def_file error on file \"%s\": filesystem doesn't support ACLs\n"),
809                jcr->last_fname);
810          return bacl_exit_error;
811 #endif
812       default:
813          Mmsg2(jcr->errmsg,
814                _("acl_delete_def_file error on file \"%s\": ERR=%s\n"),
815                jcr->last_fname, be.bstrerror());
816          return bacl_exit_error;
817       }
818    }
819
820    acl = acl_from_text(content);
821    if (acl == NULL) {
822       Mmsg2(jcr->errmsg,
823             _("acl_from_text error on file \"%s\": ERR=%s\n"),
824             jcr->last_fname, be.bstrerror());
825       Dmsg3(100, "acl_from_text error acl=%s file=%s ERR=%s\n",  
826             content, jcr->last_fname, be.bstrerror());
827       return bacl_exit_error;
828    }
829
830 #ifndef HAVE_FREEBSD_OS
831    /**
832     * FreeBSD always fails acl_valid() - at least on valid input...
833     * As it does the right thing, given valid input, just ignore acl_valid().
834     */
835    if (acl_valid(acl) != 0) {
836       Mmsg2(jcr->errmsg,
837             _("acl_valid error on file \"%s\": ERR=%s\n"),
838             jcr->last_fname, be.bstrerror());
839       Dmsg3(100, "acl_valid error acl=%s file=%s ERR=%s\n",  
840             content, jcr->last_fname, be.bstrerror());
841       acl_free(acl);
842       return bacl_exit_error;
843    }
844 #endif
845
846    /**
847     * Restore the ACLs, but don't complain about links which really should
848     * not have attributes, and the file it is linked to may not yet be restored.
849     * This is only true for the old acl streams as in the new implementation we
850     * don't save acls of symlinks (which cannot have acls anyhow)
851     */
852    if (acl_set_file(jcr->last_fname, ostype, acl) != 0 && jcr->last_type != FT_LNK) {
853       switch (errno) {
854       case ENOENT:
855          acl_free(acl);
856          return bacl_exit_ok;
857 #if defined(BACL_ENOTSUP)
858       case BACL_ENOTSUP:
859          /*
860           * If the filesystem reports it doesn't support ACLs we clear the
861           * BACL_FLAG_RESTORE_NATIVE flag so we skip ACL restores on all other files
862           * on the same filesystem. The BACL_FLAG_RESTORE_NATIVE flag gets set again
863           * when we change from one filesystem to an other.
864           */
865          jcr->acl_data->flags &= ~BACL_FLAG_RESTORE_NATIVE;
866          Mmsg1(jcr->errmsg,
867                _("acl_set_file error on file \"%s\": filesystem doesn't support ACLs\n"),
868                jcr->last_fname);
869          Dmsg2(100, "acl_set_file error acl=%s file=%s filesystem doesn't support ACLs\n",
870                content, jcr->last_fname);
871          acl_free(acl);
872          return bacl_exit_error;
873 #endif
874       default:
875          Mmsg2(jcr->errmsg,
876                _("acl_set_file error on file \"%s\": ERR=%s\n"),
877                jcr->last_fname, be.bstrerror());
878          Dmsg3(100, "acl_set_file error acl=%s file=%s ERR=%s\n",
879                content, jcr->last_fname, be.bstrerror());
880          acl_free(acl);
881          return bacl_exit_error;
882       }
883    }
884    acl_free(acl);
885    return bacl_exit_ok;
886 }
887
888 /**
889  * OS specific functions for handling different types of acl streams.
890  */
891 #if defined(HAVE_DARWIN_OS)
892 /**
893  * Define the supported ACL streams for this OS
894  */
895 static int os_access_acl_streams[1] = {
896    STREAM_ACL_DARWIN_ACCESS_ACL
897 };
898 static int os_default_acl_streams[1] = {
899    -1
900 };
901
902 static bacl_exit_code darwin_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
903 {
904 #if defined(HAVE_ACL_TYPE_EXTENDED)
905    /**
906     * On MacOS X, acl_get_file (name, ACL_TYPE_ACCESS)
907     * and acl_get_file (name, ACL_TYPE_DEFAULT)
908     * always return NULL / EINVAL.  There is no point in making
909     * these two useless calls.  The real ACL is retrieved through
910     * acl_get_file (name, ACL_TYPE_EXTENDED).
911     *
912     * Read access ACLs for files, dirs and links
913     */
914    if (generic_get_acl_from_os(jcr, BACL_TYPE_EXTENDED) == bacl_exit_fatal)
915       return bacl_exit_fatal;
916 #else
917    /**
918     * Read access ACLs for files, dirs and links
919     */
920    if (generic_get_acl_from_os(jcr, BACL_TYPE_ACCESS) == bacl_exit_fatal)
921       return bacl_exit_fatal;
922 #endif
923
924    if (jcr->acl_data->u.build->content_length > 0) {
925       return send_acl_stream(jcr, STREAM_ACL_DARWIN_ACCESS_ACL);
926    }
927    return bacl_exit_ok;
928 }
929
930 static bacl_exit_code darwin_parse_acl_streams(JCR *jcr,
931                                                int stream,
932                                                char *content,
933                                                uint32_t content_length)
934 {
935 #if defined(HAVE_ACL_TYPE_EXTENDED)
936       return generic_set_acl_on_os(jcr, BACL_TYPE_EXTENDED, content, content_length);
937 #else
938       return generic_set_acl_on_os(jcr, BACL_TYPE_ACCESS, content, content_length);
939 #endif
940 }
941
942 /*
943  * For this OS setup the build and parse function pointer to the OS specific functions.
944  */
945 static bacl_exit_code (*os_build_acl_streams)
946                       (JCR *jcr, FF_PKT *ff_pkt) =
947                       darwin_build_acl_streams;
948 static bacl_exit_code (*os_parse_acl_streams)
949                       (JCR *jcr, int stream, char *content, uint32_t content_length) =
950                       darwin_parse_acl_streams;
951
952 #elif defined(HAVE_FREEBSD_OS)
953 /*
954  * Define the supported ACL streams for these OSes
955  */
956 static int os_access_acl_streams[2] = {
957    STREAM_ACL_FREEBSD_ACCESS_ACL,
958    STREAM_ACL_FREEBSD_NFS4_ACL
959 };
960 static int os_default_acl_streams[1] = {
961    STREAM_ACL_FREEBSD_DEFAULT_ACL
962 };
963
964 static bacl_exit_code freebsd_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
965 {
966    int acl_enabled = 0;
967    bacl_type acltype = BACL_TYPE_NONE;
968    berrno be;
969
970 #if defined(_PC_ACL_NFS4)
971    /*
972     * See if filesystem supports NFS4 acls.
973     */
974    acl_enabled = pathconf(jcr->last_fname, _PC_ACL_NFS4);
975    switch (acl_enabled) {
976    case -1:
977       switch (errno) {
978       case ENOENT:
979          return bacl_exit_ok;
980       default:
981          Mmsg2(jcr->errmsg,
982                _("pathconf error on file \"%s\": ERR=%s\n"),
983                jcr->last_fname, be.bstrerror());
984          Dmsg2(100, "pathconf error file=%s ERR=%s\n",
985                jcr->last_fname, be.bstrerror());
986          return bacl_exit_error;
987       }
988    case 0:
989       break;
990    default:
991       acltype = BACL_TYPE_NFS4;
992       break;
993    }
994 #endif
995
996    if (acl_enabled == 0) {
997       /*
998        * See if filesystem supports POSIX acls.
999        */
1000       acl_enabled = pathconf(jcr->last_fname, _PC_ACL_EXTENDED);
1001       switch (acl_enabled) {
1002       case -1:
1003          switch (errno) {
1004          case ENOENT:
1005             return bacl_exit_ok;
1006          default:
1007             Mmsg2(jcr->errmsg,
1008                   _("pathconf error on file \"%s\": ERR=%s\n"),
1009                   jcr->last_fname, be.bstrerror());
1010             Dmsg2(100, "pathconf error file=%s ERR=%s\n",
1011                   jcr->last_fname, be.bstrerror());
1012             return bacl_exit_error;
1013          }
1014       case 0:
1015          break;
1016       default:
1017          acltype = BACL_TYPE_ACCESS;
1018          break;
1019       }
1020    }
1021
1022    /*
1023     * If the filesystem reports it doesn't support ACLs we clear the
1024     * BACL_FLAG_SAVE_NATIVE flag so we skip ACL saves on all other files
1025     * on the same filesystem. The BACL_FLAG_SAVE_NATIVE flag gets set again
1026     * when we change from one filesystem to an other.
1027     */
1028    if (acl_enabled == 0) {
1029       jcr->acl_data->flags &= ~BACL_FLAG_SAVE_NATIVE;
1030       pm_strcpy(jcr->acl_data->u.build->content, "");
1031       jcr->acl_data->u.build->content_length = 0;
1032       return bacl_exit_ok;
1033    }
1034
1035    /*
1036     * Based on the supported ACLs retrieve and store them.
1037     */
1038    switch (acltype) {
1039    case BACL_TYPE_NFS4:
1040       /*
1041        * Read NFS4 ACLs for files, dirs and links
1042        */
1043       if (generic_get_acl_from_os(jcr, BACL_TYPE_NFS4) == bacl_exit_fatal)
1044          return bacl_exit_fatal;
1045
1046       if (jcr->acl_data->u.build->content_length > 0) {
1047          if (send_acl_stream(jcr, STREAM_ACL_FREEBSD_NFS4_ACL) == bacl_exit_fatal)
1048             return bacl_exit_fatal;
1049       }
1050       break;
1051    case BACL_TYPE_ACCESS:
1052       /*
1053        * Read access ACLs for files, dirs and links
1054        */
1055       if (generic_get_acl_from_os(jcr, BACL_TYPE_ACCESS) == bacl_exit_fatal)
1056          return bacl_exit_fatal;
1057
1058       if (jcr->acl_data->u.build->content_length > 0) {
1059          if (send_acl_stream(jcr, STREAM_ACL_FREEBSD_ACCESS_ACL) == bacl_exit_fatal)
1060             return bacl_exit_fatal;
1061       }
1062
1063       /*
1064        * Directories can have default ACLs too
1065        */
1066       if (ff_pkt->type == FT_DIREND) {
1067          if (generic_get_acl_from_os(jcr, BACL_TYPE_DEFAULT) == bacl_exit_fatal)
1068             return bacl_exit_fatal;
1069          if (jcr->acl_data->u.build->content_length > 0) {
1070             if (send_acl_stream(jcr, STREAM_ACL_FREEBSD_DEFAULT_ACL) == bacl_exit_fatal)
1071                return bacl_exit_fatal;
1072          }
1073       }
1074       break;
1075    default:
1076       break;
1077    }
1078
1079    return bacl_exit_ok;
1080 }
1081
1082 static bacl_exit_code freebsd_parse_acl_streams(JCR *jcr,
1083                                                 int stream,
1084                                                 char *content,
1085                                                 uint32_t content_length)
1086 {
1087    int acl_enabled = 0;
1088    const char *acl_type_name;
1089    berrno be;
1090
1091    /*
1092     * First make sure the filesystem supports acls.
1093     */
1094    switch (stream) {
1095    case STREAM_UNIX_ACCESS_ACL:
1096    case STREAM_ACL_FREEBSD_ACCESS_ACL:
1097    case STREAM_UNIX_DEFAULT_ACL:
1098    case STREAM_ACL_FREEBSD_DEFAULT_ACL:
1099       acl_enabled = pathconf(jcr->last_fname, _PC_ACL_EXTENDED);
1100       acl_type_name = "POSIX";
1101       break;
1102    case STREAM_ACL_FREEBSD_NFS4_ACL:
1103 #if defined(_PC_ACL_NFS4)
1104       acl_enabled = pathconf(jcr->last_fname, _PC_ACL_NFS4);
1105 #endif
1106       acl_type_name = "NFS4";
1107       break;
1108    default:
1109       acl_type_name = "unknown";
1110       break;
1111    }
1112
1113    switch (acl_enabled) {
1114    case -1:
1115       switch (errno) {
1116       case ENOENT:
1117          return bacl_exit_ok;
1118       default:
1119          Mmsg2(jcr->errmsg,
1120                _("pathconf error on file \"%s\": ERR=%s\n"),
1121                jcr->last_fname, be.bstrerror());
1122          Dmsg3(100, "pathconf error acl=%s file=%s ERR=%s\n",
1123                content, jcr->last_fname, be.bstrerror());
1124          return bacl_exit_error;
1125       }
1126    case 0:
1127       /*
1128        * If the filesystem reports it doesn't support ACLs we clear the
1129        * BACL_FLAG_RESTORE_NATIVE flag so we skip ACL restores on all other files
1130        * on the same filesystem. The BACL_FLAG_RESTORE_NATIVE flag gets set again
1131        * when we change from one filesystem to an other.
1132        */
1133       jcr->acl_data->flags &= ~BACL_FLAG_SAVE_NATIVE;
1134       Mmsg2(jcr->errmsg,
1135             _("Trying to restore acl on file \"%s\" on filesystem without %s acl support\n"),
1136             jcr->last_fname, acl_type_name);
1137       return bacl_exit_error;
1138    default:
1139       break;
1140    }
1141
1142    /*
1143     * Restore the ACLs.
1144     */
1145    switch (stream) {
1146    case STREAM_UNIX_ACCESS_ACL:
1147    case STREAM_ACL_FREEBSD_ACCESS_ACL:
1148       return generic_set_acl_on_os(jcr, BACL_TYPE_ACCESS, content, content_length);
1149    case STREAM_UNIX_DEFAULT_ACL:
1150    case STREAM_ACL_FREEBSD_DEFAULT_ACL:
1151       return generic_set_acl_on_os(jcr, BACL_TYPE_DEFAULT, content, content_length);
1152    case STREAM_ACL_FREEBSD_NFS4_ACL:
1153       return generic_set_acl_on_os(jcr, BACL_TYPE_NFS4, content, content_length);
1154    default:
1155       break;
1156    }
1157    return bacl_exit_error;
1158 }
1159
1160 /*
1161  * For this OSes setup the build and parse function pointer to the OS specific functions.
1162  */
1163 static bacl_exit_code (*os_build_acl_streams)
1164                       (JCR *jcr, FF_PKT *ff_pkt) =
1165                       freebsd_build_acl_streams;
1166 static bacl_exit_code (*os_parse_acl_streams)
1167                       (JCR *jcr, int stream, char *content, uint32_t content_length) =
1168                       freebsd_parse_acl_streams;
1169
1170 #elif defined(HAVE_IRIX_OS) || \
1171       defined(HAVE_LINUX_OS)
1172 /*
1173  * Define the supported ACL streams for these OSes
1174  */
1175 #if defined(HAVE_IRIX_OS)
1176 static int os_access_acl_streams[1] = {
1177    STREAM_ACL_IRIX_ACCESS_ACL
1178 };
1179 static int os_default_acl_streams[1] = {
1180    STREAM_ACL_IRIX_DEFAULT_ACL
1181 };
1182 #elif defined(HAVE_LINUX_OS)
1183 static int os_access_acl_streams[1] = {
1184    STREAM_ACL_LINUX_ACCESS_ACL
1185 };
1186 static int os_default_acl_streams[1] = {
1187    STREAM_ACL_LINUX_DEFAULT_ACL
1188 };
1189 #endif
1190
1191 static bacl_exit_code generic_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
1192 {
1193    /*
1194     * Read access ACLs for files, dirs and links
1195     */
1196    if (generic_get_acl_from_os(jcr, BACL_TYPE_ACCESS) == bacl_exit_fatal)
1197       return bacl_exit_fatal;
1198
1199    if (jcr->acl_data->u.build->content_length > 0) {
1200       if (send_acl_stream(jcr, os_access_acl_streams[0]) == bacl_exit_fatal)
1201          return bacl_exit_fatal;
1202    }
1203
1204    /*
1205     * Directories can have default ACLs too
1206     */
1207    if (ff_pkt->type == FT_DIREND) {
1208       if (generic_get_acl_from_os(jcr, BACL_TYPE_DEFAULT) == bacl_exit_fatal)
1209          return bacl_exit_fatal;
1210       if (jcr->acl_data->u.build->content_length > 0) {
1211          if (send_acl_stream(jcr, os_default_acl_streams[0]) == bacl_exit_fatal)
1212             return bacl_exit_fatal;
1213       }
1214    }
1215    return bacl_exit_ok;
1216 }
1217
1218 static bacl_exit_code generic_parse_acl_streams(JCR *jcr,
1219                                                 int stream,
1220                                                 char *content,
1221                                                 uint32_t content_length)
1222 {
1223    unsigned int cnt;
1224
1225    switch (stream) {
1226    case STREAM_UNIX_ACCESS_ACL:
1227       return generic_set_acl_on_os(jcr, BACL_TYPE_ACCESS, content, content_length);
1228    case STREAM_UNIX_DEFAULT_ACL:
1229       return generic_set_acl_on_os(jcr, BACL_TYPE_DEFAULT, content, content_length);
1230    default:
1231       /*
1232        * See what type of acl it is.
1233        */
1234       for (cnt = 0; cnt < sizeof(os_access_acl_streams) / sizeof(int); cnt++) {
1235          if (os_access_acl_streams[cnt] == stream) {
1236             return generic_set_acl_on_os(jcr, BACL_TYPE_ACCESS, content, content_length);
1237          }
1238       }
1239       for (cnt = 0; cnt < sizeof(os_default_acl_streams) / sizeof(int); cnt++) {
1240          if (os_default_acl_streams[cnt] == stream) {
1241             return generic_set_acl_on_os(jcr, BACL_TYPE_DEFAULT, content, content_length);
1242          }
1243       }
1244       break;
1245    }
1246    return bacl_exit_error;
1247 }
1248
1249 /*
1250  * For this OSes setup the build and parse function pointer to the OS specific functions.
1251  */
1252 static bacl_exit_code (*os_build_acl_streams)
1253                       (JCR *jcr, FF_PKT *ff_pkt) =
1254                       generic_build_acl_streams;
1255 static bacl_exit_code (*os_parse_acl_streams)
1256                       (JCR *jcr, int stream, char *content, uint32_t content_length) =
1257                       generic_parse_acl_streams;
1258
1259 #elif defined(HAVE_OSF1_OS)
1260
1261 /*
1262  * Define the supported ACL streams for this OS
1263  */
1264 static int os_access_acl_streams[1] = {
1265    STREAM_ACL_TRU64_ACCESS_ACL
1266 };
1267 static int os_default_acl_streams[2] = {
1268    STREAM_ACL_TRU64_DEFAULT_ACL,
1269    STREAM_ACL_TRU64_DEFAULT_DIR_ACL
1270 };
1271
1272 static bacl_exit_code tru64_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
1273 {
1274    /*
1275     * Read access ACLs for files, dirs and links
1276     */
1277    if (generic_get_acl_from_os(jcr, BACL_TYPE_ACCESS) == bacl_exit_fatal) {
1278       return bacl_exit_error;
1279    if (jcr->acl_data->u.build->content_length > 0) {
1280       if (!send_acl_stream(jcr, STREAM_ACL_TRU64_ACCESS_ACL))
1281          return bacl_exit_error;
1282    }
1283    /*
1284     * Directories can have default ACLs too
1285     */
1286    if (ff_pkt->type == FT_DIREND) {
1287       if (generic_get_acl_from_os(jcr, BACL_TYPE_DEFAULT) == bacl_exit_fatal) {
1288          return bacl_exit_error;
1289       if (jcr->acl_data->u.build->content_length > 0) {
1290          if (!send_acl_stream(jcr, STREAM_ACL_TRU64_DEFAULT_ACL))
1291             return bacl_exit_error;
1292       }
1293       /**
1294        * Tru64 has next to BACL_TYPE_DEFAULT also BACL_TYPE_DEFAULT_DIR acls.
1295        * This is an inherited acl for all subdirs.
1296        * See http://www.helsinki.fi/atk/unix/dec_manuals/DOC_40D/AQ0R2DTE/DOCU_018.HTM
1297        * Section 21.5 Default ACLs 
1298        */
1299       if (generic_get_acl_from_os(jcr, BACL_TYPE_DEFAULT_DIR) == bacl_exit_fatal) {
1300          return bacl_exit_error;
1301       if (jcr->acl_data->u.build->content_length > 0) {
1302          if (!send_acl_stream(jcr, STREAM_ACL_TRU64_DEFAULT_DIR_ACL))
1303             return bacl_exit_error;
1304       }
1305    }
1306    return bacl_exit_ok;
1307 }
1308
1309 static bacl_exit_code tru64_parse_acl_streams(JCR *jcr,
1310                                               int stream,
1311                                               char *content,
1312                                               uint32_t content_length)
1313 {
1314    switch (stream) {
1315    case STREAM_UNIX_ACCESS_ACL:
1316    case STREAM_ACL_TRU64_ACCESS_ACL:
1317       return generic_set_acl_on_os(jcr, BACL_TYPE_ACCESS, content, content_length);
1318    case STREAM_UNIX_DEFAULT_ACL:
1319    case STREAM_ACL_TRU64_DEFAULT_ACL:
1320       return generic_set_acl_on_os(jcr, BACL_TYPE_DEFAULT, content, content_length);
1321    case STREAM_ACL_TRU64_DEFAULT_DIR_ACL:
1322       return generic_set_acl_on_os(jcr, BACL_TYPE_DEFAULT_DIR, content, content_length);
1323 }
1324
1325 /*
1326  * For this OS setup the build and parse function pointer to the OS specific functions.
1327  */
1328 static bacl_exit_code (*os_build_acl_streams)
1329                       (JCR *jcr, FF_PKT *ff_pkt) =
1330                       tru64_build_acl_streams;
1331 static bacl_exit_code (*os_parse_acl_streams)
1332                       (JCR *jcr, int stream, char *content, uint32_t content_length) =
1333                       tru64_parse_acl_streams;
1334
1335 #endif
1336
1337 #elif defined(HAVE_HPUX_OS)
1338 #ifdef HAVE_SYS_ACL_H
1339 #include <sys/acl.h>
1340 #else
1341 #error "configure failed to detect availability of sys/acl.h"
1342 #endif
1343
1344 #include <acllib.h>
1345
1346 /*
1347  * Define the supported ACL streams for this OS
1348  */
1349 static int os_access_acl_streams[1] = {
1350    STREAM_ACL_HPUX_ACL_ENTRY
1351 };
1352 static int os_default_acl_streams[1] = {
1353    -1
1354 };
1355
1356 /*
1357  * See if an acl is a trivial one (e.g. just the stat bits encoded as acl.)
1358  * There is no need to store those acls as we already store the stat bits too.
1359  */
1360 static bool acl_is_trivial(int count, struct acl_entry *entries, struct stat sb)
1361 {
1362    int n;
1363    struct acl_entry ace
1364
1365    for (n = 0; n < count; n++) {
1366       ace = entries[n];
1367       /*
1368        * See if this acl just is the stat mode in acl form.
1369        */
1370       if (!((ace.uid == sb.st_uid && ace.gid == ACL_NSGROUP) ||
1371             (ace.uid == ACL_NSUSER && ace.gid == sb.st_gid) ||
1372             (ace.uid == ACL_NSUSER && ace.gid == ACL_NSGROUP)))
1373          return false;
1374    }
1375    return true;
1376 }
1377
1378 /*
1379  * OS specific functions for handling different types of acl streams.
1380  */
1381 static bacl_exit_code hpux_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
1382 {
1383    int n;
1384    struct acl_entry acls[NACLENTRIES];
1385    char *acl_text;
1386    berrno be;
1387
1388    if ((n = getacl(jcr->last_fname, 0, acls)) < 0) {
1389       switch (errno) {
1390 #if defined(BACL_ENOTSUP)
1391       case BACL_ENOTSUP:
1392          /*
1393           * Not supported, just pretend there is nothing to see
1394           *
1395           * If the filesystem reports it doesn't support ACLs we clear the
1396           * BACL_FLAG_SAVE_NATIVE flag so we skip ACL saves on all other files
1397           * on the same filesystem. The BACL_FLAG_SAVE_NATIVE flag gets set again
1398           * when we change from one filesystem to an other.
1399           */
1400          jcr->acl_data->flags &= ~BACL_FLAG_SAVE_NATIVE;
1401          pm_strcpy(jcr->acl_data->u.build->content, "");
1402          jcr->acl_data->u.build->content_length = 0;
1403          return bacl_exit_ok;
1404 #endif
1405       case ENOENT:
1406          pm_strcpy(jcr->acl_data->u.build->content, "");
1407          jcr->acl_data->u.build->content_length = 0;
1408          return bacl_exit_ok;
1409       default:
1410          Mmsg2(jcr->errmsg,
1411                _("getacl error on file \"%s\": ERR=%s\n"),
1412                jcr->last_fname, be.bstrerror());
1413          Dmsg2(100, "getacl error file=%s ERR=%s\n",  
1414                jcr->last_fname, be.bstrerror());
1415
1416          pm_strcpy(jcr->acl_data->u.build->content, "");
1417          jcr->acl_data->u.build->content_length = 0;
1418          return bacl_exit_error;
1419       }
1420    }
1421    if (n == 0) {
1422       pm_strcpy(jcr->acl_data->u.build->content, "");
1423       jcr->acl_data->u.build->content_length = 0;
1424       return bacl_exit_ok;
1425    }
1426    if ((n = getacl(jcr->last_fname, n, acls)) > 0) {
1427       if (acl_is_trivial(n, acls, ff_pkt->statp)) {
1428          /*
1429           * The ACLs simply reflect the (already known) standard permissions
1430           * So we don't send an ACL stream to the SD.
1431           */
1432          pm_strcpy(jcr->acl_data->u.build->content, "");
1433          jcr->acl_data->u.build->content_length = 0;
1434          return bacl_exit_ok;
1435       }
1436       if ((acl_text = acltostr(n, acls, FORM_SHORT)) != NULL) {
1437          jcr->acl_data->u.build->content_length =
1438          pm_strcpy(jcr->acl_data->u.build->content, acl_text);
1439          actuallyfree(acl_text);
1440
1441          return send_acl_stream(jcr, STREAM_ACL_HPUX_ACL_ENTRY);
1442       }
1443       Mmsg2(jcr->errmsg,
1444             _("acltostr error on file \"%s\": ERR=%s\n"),
1445             jcr->last_fname, be.bstrerror());
1446       Dmsg3(100, "acltostr error acl=%s file=%s ERR=%s\n",  
1447             jcr->acl_data->u.build->content, jcr->last_fname, be.bstrerror());
1448       return bacl_exit_error;
1449    }
1450    return bacl_exit_error;
1451 }
1452
1453 static bacl_exit_code hpux_parse_acl_streams(JCR *jcr,
1454                                              int stream,
1455                                              char *content,
1456                                              uint32_t content_length)
1457 {
1458    int n, stat;
1459    struct acl_entry acls[NACLENTRIES];
1460    berrno be;
1461
1462    n = strtoacl(content, 0, NACLENTRIES, acls, ACL_FILEOWNER, ACL_FILEGROUP);
1463    if (n <= 0) {
1464       Mmsg2(jcr->errmsg,
1465             _("strtoacl error on file \"%s\": ERR=%s\n"),
1466             jcr->last_fname, be.bstrerror());
1467       Dmsg3(100, "strtoacl error acl=%s file=%s ERR=%s\n",  
1468             content, jcr->last_fname, be.bstrerror());
1469       return bacl_exit_error;
1470    }
1471    if (strtoacl(content, n, NACLENTRIES, acls, ACL_FILEOWNER, ACL_FILEGROUP) != n) {
1472       Mmsg2(jcr->errmsg,
1473             _("strtoacl error on file \"%s\": ERR=%s\n"),
1474             jcr->last_fname, be.bstrerror());
1475       Dmsg3(100, "strtoacl error acl=%s file=%s ERR=%s\n",  
1476             content, jcr->last_fname, be.bstrerror());
1477
1478       return bacl_exit_error;
1479    }
1480    /**
1481     * Restore the ACLs, but don't complain about links which really should
1482     * not have attributes, and the file it is linked to may not yet be restored.
1483     * This is only true for the old acl streams as in the new implementation we
1484     * don't save acls of symlinks (which cannot have acls anyhow)
1485     */
1486    if (setacl(jcr->last_fname, n, acls) != 0 &&
1487        jcr->last_type != FT_LNK) {
1488       switch (errno) {
1489       case ENOENT:
1490          return bacl_exit_ok;
1491 #if defined(BACL_ENOTSUP)
1492       case BACL_ENOTSUP:
1493          /*
1494           * If the filesystem reports it doesn't support ACLs we clear the
1495           * BACL_FLAG_RESTORE_NATIVE flag so we skip ACL restores on all other files
1496           * on the same filesystem. The BACL_FLAG_RESTORE_NATIVE flag gets set again
1497           * when we change from one filesystem to an other.
1498           */
1499          jcr->acl_data->flags &= ~BACL_FLAG_SAVE_NATIVE;
1500          Mmsg1(jcr->errmsg,
1501                _("setacl error on file \"%s\": filesystem doesn't support ACLs\n"),
1502                jcr->last_fname);
1503          Dmsg2(100, "setacl error acl=%s file=%s filesystem doesn't support ACLs\n",
1504                content, jcr->last_fname);
1505          return bacl_exit_error;
1506 #endif
1507       default:
1508          Mmsg2(jcr->errmsg,
1509                _("setacl error on file \"%s\": ERR=%s\n"),
1510                jcr->last_fname, be.bstrerror());
1511          Dmsg3(100, "setacl error acl=%s file=%s ERR=%s\n",
1512                content, jcr->last_fname, be.bstrerror());
1513          return bacl_exit_error;
1514       }
1515    }
1516    return bacl_exit_ok;
1517 }
1518
1519 /*
1520  * For this OS setup the build and parse function pointer to the OS specific functions.
1521  */
1522 static bacl_exit_code (*os_build_acl_streams)
1523                       (JCR *jcr, FF_PKT *ff_pkt) =
1524                       hpux_build_acl_streams;
1525 static bacl_exit_code (*os_parse_acl_streams)
1526                       (JCR *jcr, int stream, char *content, uint32_t content_length) =
1527                       hpux_parse_acl_streams;
1528
1529 #elif defined(HAVE_SUN_OS)
1530 #ifdef HAVE_SYS_ACL_H
1531 #include <sys/acl.h>
1532 #else
1533 #error "configure failed to detect availability of sys/acl.h"
1534 #endif
1535
1536 #if defined(HAVE_EXTENDED_ACL)
1537 /**
1538  * We define some internals of the Solaris acl libs here as those
1539  * are not exposed yet. Probably because they want us to see the
1540  * acls as opague data. But as we need to support different platforms
1541  * and versions of Solaris we need to expose some data to be able
1542  * to determine the type of acl used to stuff it into the correct
1543  * data stream. I know this is far from portable, but maybe the
1544  * proper interface is exposed later on and we can get ride of
1545  * this kludge. Newer versions of Solaris include sys/acl_impl.h
1546  * which has implementation details of acls, if thats included we
1547  * don't have to define it ourself.
1548  */
1549 #if !defined(_SYS_ACL_IMPL_H)
1550 typedef enum acl_type {
1551    ACLENT_T = 0,
1552    ACE_T = 1
1553 } acl_type_t;
1554 #endif
1555
1556 /**
1557  * Two external references to functions in the libsec library function not in current include files.
1558  */
1559 extern "C" {
1560 int acl_type(acl_t *);
1561 char *acl_strerror(int);
1562 }
1563
1564 /*
1565  * Define the supported ACL streams for this OS
1566  */
1567 static int os_access_acl_streams[2] = {
1568    STREAM_ACL_SOLARIS_ACLENT,
1569    STREAM_ACL_SOLARIS_ACE
1570 };
1571 static int os_default_acl_streams[1] = {
1572    -1
1573 };
1574
1575 /**
1576  * As the new libsec interface with acl_totext and acl_fromtext also handles
1577  * the old format from acltotext we can use the new functions even
1578  * for acls retrieved and stored in the database with older fd versions. If the
1579  * new interface is not defined (Solaris 9 and older we fall back to the old code)
1580  */
1581 static bacl_exit_code solaris_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
1582 {
1583    int acl_enabled, flags;
1584    acl_t *aclp;
1585    char *acl_text;
1586    bacl_exit_code stream_status = bacl_exit_error;
1587    berrno be;
1588
1589    /*
1590     * See if filesystem supports acls.
1591     */
1592    acl_enabled = pathconf(jcr->last_fname, _PC_ACL_ENABLED);
1593    switch (acl_enabled) {
1594    case 0:
1595       /*
1596        * If the filesystem reports it doesn't support ACLs we clear the
1597        * BACL_FLAG_SAVE_NATIVE flag so we skip ACL saves on all other files
1598        * on the same filesystem. The BACL_FLAG_SAVE_NATIVE flag gets set again
1599        * when we change from one filesystem to an other.
1600        */
1601       jcr->acl_data->flags &= ~BACL_FLAG_SAVE_NATIVE;
1602       pm_strcpy(jcr->acl_data->u.build->content, "");
1603       jcr->acl_data->u.build->content_length = 0;
1604       return bacl_exit_ok;
1605    case -1:
1606       switch (errno) {
1607       case ENOENT:
1608          return bacl_exit_ok;
1609       default:
1610          Mmsg2(jcr->errmsg,
1611                _("pathconf error on file \"%s\": ERR=%s\n"),
1612                jcr->last_fname, be.bstrerror());
1613          Dmsg2(100, "pathconf error file=%s ERR=%s\n",  
1614                jcr->last_fname, be.bstrerror());
1615          return bacl_exit_error;
1616       }
1617    default:
1618       break;
1619    }
1620
1621    /*
1622     * Get ACL info: don't bother allocating space if there is only a trivial ACL.
1623     */
1624    if (acl_get(jcr->last_fname, ACL_NO_TRIVIAL, &aclp) != 0) {
1625       switch (errno) {
1626       case ENOENT:
1627          return bacl_exit_ok;
1628       default:
1629          Mmsg2(jcr->errmsg,
1630                _("acl_get error on file \"%s\": ERR=%s\n"),
1631                jcr->last_fname, acl_strerror(errno));
1632          Dmsg2(100, "acl_get error file=%s ERR=%s\n",  
1633                jcr->last_fname, acl_strerror(errno));
1634          return bacl_exit_error;
1635       }
1636    }
1637
1638    if (!aclp) {
1639       /*
1640        * The ACLs simply reflect the (already known) standard permissions
1641        * So we don't send an ACL stream to the SD.
1642        */
1643       pm_strcpy(jcr->acl_data->u.build->content, "");
1644       jcr->acl_data->u.build->content_length = 0;
1645       return bacl_exit_ok;
1646    }
1647
1648 #if defined(ACL_SID_FMT)
1649    /*
1650     * New format flag added in newer Solaris versions.
1651     */
1652    flags = ACL_APPEND_ID | ACL_COMPACT_FMT | ACL_SID_FMT;
1653 #else
1654    flags = ACL_APPEND_ID | ACL_COMPACT_FMT;
1655 #endif /* ACL_SID_FMT */
1656
1657    if ((acl_text = acl_totext(aclp, flags)) != NULL) {
1658       jcr->acl_data->u.build->content_length =
1659       pm_strcpy(jcr->acl_data->u.build->content, acl_text);
1660       actuallyfree(acl_text);
1661
1662       switch (acl_type(aclp)) {
1663       case ACLENT_T:
1664          stream_status = send_acl_stream(jcr, STREAM_ACL_SOLARIS_ACLENT);
1665          break;
1666       case ACE_T:
1667          stream_status = send_acl_stream(jcr, STREAM_ACL_SOLARIS_ACE);
1668          break;
1669       default:
1670          break;
1671       }
1672
1673       acl_free(aclp);
1674    }
1675    return stream_status;
1676 }
1677
1678 static bacl_exit_code solaris_parse_acl_streams(JCR *jcr,
1679                                                 int stream,
1680                                                 char *content,
1681                                                 uint32_t content_length)
1682 {
1683    acl_t *aclp;
1684    int acl_enabled, error;
1685    berrno be;
1686
1687    switch (stream) {
1688    case STREAM_UNIX_ACCESS_ACL:
1689    case STREAM_ACL_SOLARIS_ACLENT:
1690    case STREAM_ACL_SOLARIS_ACE:
1691       /*
1692        * First make sure the filesystem supports acls.
1693        */
1694       acl_enabled = pathconf(jcr->last_fname, _PC_ACL_ENABLED);
1695       switch (acl_enabled) {
1696       case 0:
1697          /*
1698           * If the filesystem reports it doesn't support ACLs we clear the
1699           * BACL_FLAG_RESTORE_NATIVE flag so we skip ACL restores on all other files
1700           * on the same filesystem. The BACL_FLAG_RESTORE_NATIVE flag gets set again
1701           * when we change from one filesystem to an other.
1702           */
1703          jcr->acl_data->flags &= ~BACL_FLAG_RESTORE_NATIVE;
1704          Mmsg1(jcr->errmsg,
1705                _("Trying to restore acl on file \"%s\" on filesystem without acl support\n"),
1706                jcr->last_fname);
1707          return bacl_exit_error;
1708       case -1:
1709          switch (errno) {
1710          case ENOENT:
1711             return bacl_exit_ok;
1712          default:
1713             Mmsg2(jcr->errmsg,
1714                   _("pathconf error on file \"%s\": ERR=%s\n"),
1715                   jcr->last_fname, be.bstrerror());
1716             Dmsg3(100, "pathconf error acl=%s file=%s ERR=%s\n",  
1717                   content, jcr->last_fname, be.bstrerror());
1718             return bacl_exit_error;
1719          }
1720       default:
1721          /*
1722           * On a filesystem with ACL support make sure this particular ACL type can be restored.
1723           */
1724          switch (stream) {
1725          case STREAM_ACL_SOLARIS_ACLENT:
1726             /*
1727              * An aclent can be restored on filesystems with _ACL_ACLENT_ENABLED or _ACL_ACE_ENABLED support.
1728              */
1729             if ((acl_enabled & (_ACL_ACLENT_ENABLED | _ACL_ACE_ENABLED)) == 0) {
1730                Mmsg1(jcr->errmsg,
1731                      _("Trying to restore acl on file \"%s\" on filesystem without aclent acl support\n"),
1732                      jcr->last_fname);
1733                return bacl_exit_error;
1734             }
1735             break;
1736          case STREAM_ACL_SOLARIS_ACE:
1737             /*
1738              * An ace can only be restored on a filesystem with _ACL_ACE_ENABLED support.
1739              */
1740             if ((acl_enabled & _ACL_ACE_ENABLED) == 0) {
1741                Mmsg1(jcr->errmsg,
1742                      _("Trying to restore acl on file \"%s\" on filesystem without ace acl support\n"),
1743                      jcr->last_fname);
1744                return bacl_exit_error;
1745             }
1746             break;
1747          default:
1748             /*
1749              * Stream id which doesn't describe the type of acl which is encoded.
1750              */
1751             break;
1752          }
1753          break;
1754       }
1755
1756       if ((error = acl_fromtext(content, &aclp)) != 0) {
1757          Mmsg2(jcr->errmsg,
1758                _("acl_fromtext error on file \"%s\": ERR=%s\n"),
1759                jcr->last_fname, acl_strerror(error));
1760          Dmsg3(100, "acl_fromtext error acl=%s file=%s ERR=%s\n",  
1761                content, jcr->last_fname, acl_strerror(error));
1762          return bacl_exit_error;
1763       }
1764
1765       /*
1766        * Validate that the conversion gave us the correct acl type.
1767        */
1768       switch (stream) {
1769       case STREAM_ACL_SOLARIS_ACLENT:
1770          if (acl_type(aclp) != ACLENT_T) {
1771             Mmsg1(jcr->errmsg,
1772                   _("wrong encoding of acl type in acl stream on file \"%s\"\n"),
1773                   jcr->last_fname);
1774             return bacl_exit_error;
1775          }
1776          break;
1777       case STREAM_ACL_SOLARIS_ACE:
1778          if (acl_type(aclp) != ACE_T) {
1779             Mmsg1(jcr->errmsg,
1780                   _("wrong encoding of acl type in acl stream on file \"%s\"\n"),
1781                   jcr->last_fname);
1782             return bacl_exit_error;
1783          }
1784          break;
1785       default:
1786          /*
1787           * Stream id which doesn't describe the type of acl which is encoded.
1788           */
1789          break;
1790       }
1791
1792       /**
1793        * Restore the ACLs, but don't complain about links which really should
1794        * not have attributes, and the file it is linked to may not yet be restored.
1795        * This is only true for the old acl streams as in the new implementation we
1796        * don't save acls of symlinks (which cannot have acls anyhow)
1797        */
1798       if ((error = acl_set(jcr->last_fname, aclp)) == -1 && jcr->last_type != FT_LNK) {
1799          switch (errno) {
1800          case ENOENT:
1801             acl_free(aclp);
1802             return bacl_exit_ok;
1803          default:
1804             Mmsg2(jcr->errmsg,
1805                   _("acl_set error on file \"%s\": ERR=%s\n"),
1806                   jcr->last_fname, acl_strerror(error));
1807             Dmsg3(100, "acl_set error acl=%s file=%s ERR=%s\n",  
1808                   content, jcr->last_fname, acl_strerror(error));
1809             acl_free(aclp);
1810             return bacl_exit_error;
1811          }
1812       }
1813
1814       acl_free(aclp);
1815       return bacl_exit_ok;
1816    default:
1817       return bacl_exit_error;
1818    } /* end switch (stream) */
1819 }
1820
1821 #else /* HAVE_EXTENDED_ACL */
1822
1823 /*
1824  * Define the supported ACL streams for this OS
1825  */
1826 static int os_access_acl_streams[1] = {
1827    STREAM_ACL_SOLARIS_ACLENT
1828 };
1829 static int os_default_acl_streams[1] = {
1830    -1
1831 };
1832
1833 /*
1834  * See if an acl is a trivial one (e.g. just the stat bits encoded as acl.)
1835  * There is no need to store those acls as we already store the stat bits too.
1836  */
1837 static bool acl_is_trivial(int count, aclent_t *entries)
1838 {
1839    int n;
1840    aclent_t *ace;
1841
1842    for (n = 0; n < count; n++) {
1843       ace = &entries[n];
1844
1845       if (!(ace->a_type == USER_OBJ ||
1846             ace->a_type == GROUP_OBJ ||
1847             ace->a_type == OTHER_OBJ ||
1848             ace->a_type == CLASS_OBJ))
1849         return false;
1850    }
1851    return true;
1852 }
1853
1854 /*
1855  * OS specific functions for handling different types of acl streams.
1856  */
1857 static bacl_exit_code solaris_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
1858 {
1859    int n;
1860    aclent_t *acls;
1861    char *acl_text;
1862    berrno be;
1863
1864    n = acl(jcr->last_fname, GETACLCNT, 0, NULL);
1865    if (n < MIN_ACL_ENTRIES)
1866       return bacl_exit_error;
1867
1868    acls = (aclent_t *)malloc(n * sizeof(aclent_t));
1869    if (acl(jcr->last_fname, GETACL, n, acls) == n) {
1870       if (acl_is_trivial(n, acls)) {
1871          /*
1872           * The ACLs simply reflect the (already known) standard permissions
1873           * So we don't send an ACL stream to the SD.
1874           */
1875          free(acls);
1876          pm_strcpy(jcr->acl_data->u.build->content, "");
1877          jcr->acl_data->u.build->content_length = 0;
1878          return bacl_exit_ok;
1879       }
1880
1881       if ((acl_text = acltotext(acls, n)) != NULL) {
1882          jcr->acl_data->u.build->content_length =
1883          pm_strcpy(jcr->acl_data->u.build->content, acl_text);
1884          actuallyfree(acl_text);
1885          free(acls);
1886          return send_acl_stream(jcr, STREAM_ACL_SOLARIS_ACLENT);
1887       }
1888
1889       Mmsg2(jcr->errmsg,
1890             _("acltotext error on file \"%s\": ERR=%s\n"),
1891             jcr->last_fname, be.bstrerror());
1892       Dmsg3(100, "acltotext error acl=%s file=%s ERR=%s\n",  
1893             jcr->acl_data->u.build->content, jcr->last_fname, be.bstrerror());
1894    }
1895
1896    free(acls);
1897    return bacl_exit_error;
1898 }
1899
1900 static bacl_exit_code solaris_parse_acl_streams(JCR *jcr,
1901                                                 int stream,
1902                                                 char *content,
1903                                                 uint32_t content_length)
1904 {
1905    int n;
1906    aclent_t *acls;
1907    berrno be;
1908
1909    acls = aclfromtext(content, &n);
1910    if (!acls) {
1911       Mmsg2(jcr->errmsg,
1912             _("aclfromtext error on file \"%s\": ERR=%s\n"),
1913             jcr->last_fname, be.bstrerror());
1914       Dmsg3(100, "aclfromtext error acl=%s file=%s ERR=%s\n",  
1915             content, jcr->last_fname, be.bstrerror());
1916       return bacl_exit_error;
1917    }
1918
1919    /*
1920     * Restore the ACLs, but don't complain about links which really should
1921     * not have attributes, and the file it is linked to may not yet be restored.
1922     */
1923    if (acl(jcr->last_fname, SETACL, n, acls) == -1 && jcr->last_type != FT_LNK) {
1924       switch (errno) {
1925       case ENOENT:
1926          actuallyfree(acls);
1927          return bacl_exit_ok;
1928       default:
1929          Mmsg2(jcr->errmsg,
1930                _("acl(SETACL) error on file \"%s\": ERR=%s\n"),
1931                jcr->last_fname, be.bstrerror());
1932          Dmsg3(100, "acl(SETACL) error acl=%s file=%s ERR=%s\n",
1933                content, jcr->last_fname, be.bstrerror());
1934          actuallyfree(acls);
1935          return bacl_exit_error;
1936       }
1937    }
1938    actuallyfree(acls);
1939    return bacl_exit_ok;
1940 }
1941 #endif /* HAVE_EXTENDED_ACL */
1942
1943 /*
1944  * For this OS setup the build and parse function pointer to the OS specific functions.
1945  */
1946 static bacl_exit_code (*os_build_acl_streams)
1947                       (JCR *jcr, FF_PKT *ff_pkt) =
1948                       solaris_build_acl_streams;
1949 static bacl_exit_code (*os_parse_acl_streams)
1950                       (JCR *jcr, int stream, char *content, uint32_t content_length) =
1951                       solaris_parse_acl_streams;
1952
1953 #endif /* HAVE_SUN_OS */
1954 #endif /* HAVE_ACL */
1955
1956 /*
1957  * Entry points when compiled with support for ACLs on a supported platform.
1958  */
1959
1960 /**
1961  * Read and send an ACL for the last encountered file.
1962  */
1963 bacl_exit_code build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
1964 {
1965    /*
1966     * See if we are changing from one device to an other.
1967     * We save the current device we are restoring to and compare
1968     * it with the current st_dev in the last stat performed on
1969     * the file we are currently storing.
1970     */
1971    if (jcr->acl_data->current_dev != ff_pkt->statp.st_dev) {
1972       /*
1973        * Reset the acl save flags.
1974        */
1975       jcr->acl_data->flags = 0;
1976
1977       jcr->acl_data->flags |= BACL_FLAG_SAVE_NATIVE;
1978
1979       /**
1980        * Save that we started scanning a new filesystem.
1981        */
1982       jcr->acl_data->current_dev = ff_pkt->statp.st_dev;
1983    }
1984
1985 #if defined(HAVE_ACL)
1986    /*
1987     * See if the BACL_FLAG_SAVE_NATIVE flag is set which lets us know if we should
1988     * save native ACLs.
1989     */
1990    if (jcr->acl_data->flags & BACL_FLAG_SAVE_NATIVE) {
1991       /*
1992        * Call the appropriate function.
1993        */
1994       if (os_build_acl_streams) {
1995          return os_build_acl_streams(jcr, ff_pkt);
1996       }
1997    } else {
1998       return bacl_exit_ok;
1999    }
2000 #endif
2001    return bacl_exit_error;
2002 }
2003
2004 bacl_exit_code parse_acl_streams(JCR *jcr,
2005                                  int stream,
2006                                  char *content,
2007                                  uint32_t content_length)
2008 {
2009    int ret;
2010    berrno be;
2011    struct stat st;
2012    unsigned int cnt;
2013
2014    /*
2015     * See if we are changing from one device to an other.
2016     * We save the current device we are restoring to and compare
2017     * it with the current st_dev in the last stat performed on
2018     * the file we are currently restoring.
2019     */
2020    ret = lstat(jcr->last_fname, &st);
2021    switch (ret) {
2022    case -1:
2023       switch (errno) {
2024       case ENOENT:
2025          return bacl_exit_ok;
2026       default:
2027          Mmsg2(jcr->errmsg,
2028                _("Unable to stat file \"%s\": ERR=%s\n"),
2029                jcr->last_fname, be.bstrerror());
2030          Dmsg2(100, "Unable to stat file \"%s\": ERR=%s\n",
2031                jcr->last_fname, be.bstrerror());
2032          return bacl_exit_error;
2033       }
2034       break;
2035    case 0:
2036       break;
2037    }
2038    if (jcr->acl_data->current_dev != st.st_dev) {
2039       /*
2040        * Reset the acl save flags.
2041        */
2042       jcr->acl_data->flags = 0;
2043       jcr->acl_data->flags |= BACL_FLAG_RESTORE_NATIVE;
2044
2045       /*
2046        * Save that we started restoring to a new filesystem.
2047        */
2048       jcr->acl_data->current_dev = st.st_dev;
2049    }
2050
2051    switch (stream) {
2052 #if defined(HAVE_ACL)
2053    case STREAM_UNIX_ACCESS_ACL:
2054    case STREAM_UNIX_DEFAULT_ACL:
2055       /*
2056        * Handle legacy ACL streams.
2057        */
2058       if ((jcr->acl_data->flags & BACL_FLAG_RESTORE_NATIVE) && os_parse_acl_streams) {
2059          return os_parse_acl_streams(jcr, stream, content, content_length);
2060       } else {
2061          /*
2062           * Increment error count but don't log an error again for the same filesystem.
2063           */
2064          jcr->acl_data->u.parse->nr_errors++;
2065          return bacl_exit_ok;
2066       }
2067       break;
2068    default:
2069       if ((jcr->acl_data->flags & BACL_FLAG_RESTORE_NATIVE) && os_parse_acl_streams) {
2070          /*
2071           * Walk the os_access_acl_streams array with the supported Access ACL streams for this OS.
2072           */
2073          for (cnt = 0; cnt < sizeof(os_access_acl_streams) / sizeof(int); cnt++) {
2074             if (os_access_acl_streams[cnt] == stream) {
2075                return os_parse_acl_streams(jcr, stream, content, content_length);
2076             }
2077          }
2078          /*
2079           * Walk the os_default_acl_streams array with the supported Default ACL streams for this OS.
2080           */
2081          for (cnt = 0; cnt < sizeof(os_default_acl_streams) / sizeof(int); cnt++) {
2082             if (os_default_acl_streams[cnt] == stream) {
2083                return os_parse_acl_streams(jcr, stream, content, content_length);
2084             }
2085          }
2086       } else {
2087          /*
2088           * Increment error count but don't log an error again for the same filesystem.
2089           */
2090          jcr->acl_data->u.parse->nr_errors++;
2091          return bacl_exit_ok;
2092       }
2093       break;
2094 #else
2095    default:
2096       break;
2097 #endif
2098    }
2099    Qmsg2(jcr, M_WARNING, 0,
2100       _("Can't restore ACLs of %s - incompatible acl stream encountered - %d\n"),
2101       jcr->last_fname, stream);
2102    return bacl_exit_error;
2103 }
2104 #endif