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