]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/filed/xattr.c
Moved list of supported xattr to start of per OS implementation like in acl.c
[bacula/bacula] / bacula / src / filed / xattr.c
1 /*
2    Bacula® - The Network Backup Solution
3
4    Copyright (C) 2008-2009 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 two of the GNU 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 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 Extended Attributes for bacula.
30  *
31  * Extended Attributes are so OS specific we only restore Extended Attributes if
32  * they were saved using a filed on the same platform.
33  *
34  * Currently we support the following OSes:
35  *   - FreeBSD (Extended Attributes)
36  *   - Darwin (Extended Attributes)
37  *   - Linux (Extended Attributes)
38  *   - NetBSD (Extended Attributes)
39  *   - Solaris (Extended Attributes and Extensible Attributes)
40  *
41  *   Written by Marco van Wieringen, November MMVIII
42  *
43  *   Version $Id$
44  */
45
46 #include "bacula.h"
47 #include "filed.h"
48 #include "xattr.h"
49
50 #if !defined(HAVE_XATTR)
51 /*
52  * Entry points when compiled without support for XATTRs or on an unsupported platform.
53  */
54 bsub_exit_code build_xattr_streams(JCR *jcr, FF_PKT *ff_pkt)
55 {
56    return bsub_exit_fatal;
57 }
58
59 bsub_exit_code parse_xattr_streams(JCR *jcr, int stream)
60 {
61    return bsub_exit_fatal;
62 }
63 #else
64 /*
65  * Send a XATTR stream to the SD.
66  */
67 static bsub_exit_code send_xattr_stream(JCR *jcr, int stream)
68 {
69    BSOCK *sd = jcr->store_bsock;
70    POOLMEM *msgsave;
71 #ifdef FD_NO_SEND_TEST
72    return bsub_exit_ok;
73 #endif
74
75    /*
76     * Sanity check
77     */
78    if (jcr->xattr_data_len <= 0)
79       return bsub_exit_ok;
80
81    /*
82     * Send header
83     */
84    if (!sd->fsend("%ld %d 0", jcr->JobFiles, stream)) {
85       Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
86             sd->bstrerror());
87       return bsub_exit_fatal;
88    }
89
90    /*
91     * Send the buffer to the storage deamon
92     */
93    Dmsg1(400, "Backing up XATTR <%s>\n", jcr->xattr_data);
94    msgsave = sd->msg;
95    sd->msg = jcr->xattr_data;
96    sd->msglen = jcr->xattr_data_len;
97    if (!sd->send()) {
98       sd->msg = msgsave;
99       sd->msglen = 0;
100       Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
101             sd->bstrerror());
102       return bsub_exit_fatal;
103    }
104
105    jcr->JobBytes += sd->msglen;
106    sd->msg = msgsave;
107    if (!sd->signal(BNET_EOD)) {
108       Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
109             sd->bstrerror());
110       return bsub_exit_fatal;
111    }
112    Dmsg1(200, "XATTR of file: %s successfully backed up!\n", jcr->last_fname);
113    return bsub_exit_ok;
114 }
115
116 /*
117  * This is a supported OS, See what kind of interface we should use.
118  * Start with the generic interface used by most OS-es.
119  */
120 #if defined(HAVE_DARWIN_OS) \
121    || defined(HAVE_FREEBSD_OS) \
122    || defined(HAVE_LINUX_OS) \
123    || defined(HAVE_NETBSD_OS)
124        
125 #ifdef HAVE_SYS_XATTR_H
126 #include <sys/xattr.h>
127 #endif
128
129 /*
130  * All these os-es have 1 xattr stream.
131  */
132 #if defined(HAVE_DARWIN_OS)
133 static int os_default_xattr_streams[1] = { STREAM_XATTR_DARWIN };
134 #elif defined(HAVE_FREEBSD_OS)
135 static int os_default_xattr_streams[1] = { STREAM_XATTR_FREEBSD };
136 #elif defined(HAVE_LINUX_OS)
137 static int os_default_xattr_streams[1] = { STREAM_XATTR_LINUX };
138 #elif defined(HAVE_NETBSD_OS)
139 static int os_default_xattr_streams[1] = { STREAM_XATTR_NETBSD };
140 #endif
141
142 /*
143  * OSX doesn't have llistxattr, lgetxattr and lsetxattr but has
144  * listxattr, getxattr and setxattr with an extra options argument
145  * which mimics the l variants of the functions when we specify
146  * XATTR_NOFOLLOW as the options value.
147  */
148 #if defined(HAVE_DARWIN_OS)
149    #define llistxattr(path, list, size) listxattr((path), (list), (size), XATTR_NOFOLLOW)
150    #define lgetxattr(path, name, value, size) getxattr((path), (name), (value), (size), 0, XATTR_NOFOLLOW)
151    #define lsetxattr(path, name, value, size, flags) setxattr((path), (name), (value), (size), (flags), XATTR_NOFOLLOW)
152 #else
153    /*
154     * Fallback to the non l-functions when those are not available.
155     */
156    #if defined(HAVE_GETXATTR) && !defined(HAVE_LGETXATTR)
157    #define lgetxattr getxattr
158    #endif
159    #if defined(HAVE_SETXATTR) && !defined(HAVE_LSETXATTR)
160    #define lsetxattr setxattr
161    #endif
162    #if defined(HAVE_LISTXATTR) && !defined(HAVE_LLISTXATTR)
163    #define llistxattr listxattr
164    #endif
165 #endif
166
167 static void xattr_drop_internal_table(xattr_t *xattr_value_list)
168 {
169    xattr_t *current_xattr;
170
171    /*
172     * Walk the list of xattrs and free allocated memory on traversing.
173     */
174    for (current_xattr = xattr_value_list;
175         current_xattr != (xattr_t *)NULL;
176         current_xattr++) {
177       /*
178        * See if we can shortcut.
179        */
180       if (current_xattr->magic != XATTR_MAGIC)
181          break;
182
183       free(current_xattr->name);
184
185       if (current_xattr->value_length > 0)
186          free(current_xattr->value);
187    }
188
189    /*
190     * Free the array of control structs.
191     */
192    free(xattr_value_list);
193 }
194
195 /*
196  * The xattr stream for OSX, FreeBSD, Linux and NetBSD is a serialized stream of bytes
197  * which encodes one or more xattr_t structures.
198  *
199  * The Serialized stream consists of the following elements:
200  *    magic - A magic string which makes it easy to detect any binary incompatabilites
201  *    name_length - The length of the following xattr name
202  *    name - The name of the extended attribute
203  *    value_length - The length of the following xattr data
204  *    value - The actual content of the extended attribute
205  *
206  * This is repeated 1 or more times.
207  * 
208  */
209 static uint32_t serialize_xattr_stream(JCR *jcr, uint32_t expected_serialize_len, xattr_t *xattr_value_list)
210 {
211    xattr_t *current_xattr;
212    ser_declare;
213
214    /*
215     * Make sure the serialized stream fits in the poolmem buffer.
216     * We allocate some more to be sure the stream is gonna fit.
217     */
218    jcr->xattr_data = check_pool_memory_size(jcr->xattr_data, expected_serialize_len + 10);
219    ser_begin(jcr->xattr_data, expected_serialize_len + 10);
220
221    /*
222     * Walk the list of xattrs and serialize the data.
223     */
224    for (current_xattr = xattr_value_list; current_xattr != (xattr_t *)NULL; current_xattr++) {
225       /*
226        * See if we can shortcut.
227        */
228       if (current_xattr->magic != XATTR_MAGIC)
229          break;
230
231       ser_uint32(current_xattr->magic);
232       ser_uint32(current_xattr->name_length);
233       ser_bytes(current_xattr->name, current_xattr->name_length);
234
235       ser_uint32(current_xattr->value_length);
236       ser_bytes(current_xattr->value, current_xattr->value_length);
237    }
238
239    ser_end(jcr->xattr_data, expected_serialize_len + 10);
240    jcr->xattr_data_len = ser_length(jcr->xattr_data);
241    return jcr->xattr_data_len;
242 }
243
244 static bsub_exit_code generic_xattr_build_streams(JCR *jcr, FF_PKT *ff_pkt, int default_stream)
245 {
246    int count = 0;
247    int32_t xattr_list_len,
248            xattr_value_len;
249    uint32_t expected_serialize_len = 0;
250    char *xattr_list, *bp;
251    xattr_t *xattr_value_list, *current_xattr;
252
253    /*
254     * First get the length of the available list with extended attributes.
255     */
256    xattr_list_len = llistxattr(jcr->last_fname, NULL, 0);
257    if (xattr_list_len < 0) {
258       switch (errno) {
259       case ENOENT:
260          return bsub_exit_nok;
261       default:
262          berrno be;
263          Jmsg2(jcr, M_ERROR, 0, _("llistxattr error on file \"%s\": ERR=%s\n"),
264             jcr->last_fname, be.bstrerror());
265          Dmsg2(100, "llistxattr error file=%s ERR=%s\n",
266             jcr->last_fname, be.bstrerror());
267          return bsub_exit_nok;
268       }
269    } else if (xattr_list_len == 0) {
270       return bsub_exit_ok;
271    }
272
273    /*
274     * Allocate room for the extented attribute list.
275     */
276    xattr_list = (char *)malloc(xattr_list_len + 1);
277    memset((caddr_t)xattr_list, 0, xattr_list_len + 1);
278
279    /*
280     * Get the actual list of extended attributes names for a file.
281     */
282    xattr_list_len = llistxattr(jcr->last_fname, xattr_list, xattr_list_len);
283    if (xattr_list_len < 0) {
284       switch (errno) {
285       case ENOENT:
286          free(xattr_list);
287          return bsub_exit_nok;
288       default:
289          berrno be;
290          Jmsg2(jcr, M_ERROR, 0, _("llistxattr error on file \"%s\": ERR=%s\n"),
291             jcr->last_fname, be.bstrerror());
292          Dmsg2(100, "llistxattr error file=%s ERR=%s\n",
293             jcr->last_fname, be.bstrerror());
294          free(xattr_list);
295          return bsub_exit_nok;
296       }
297    }
298    xattr_list[xattr_list_len] = '\0';
299
300    /*
301     * Count the number of extended attributes on a file.
302     */
303    bp = xattr_list;
304    while ((bp - xattr_list) + 1 < xattr_list_len) {
305 #if defined(HAVE_LINUX_OS)
306       /*
307        * On Linux you also get the acls in the extented attribute list.
308        * So we check if we are already backing up acls and if we do we
309        * don't store the extended attribute with the same info.
310        */
311       if ((ff_pkt->flags & FO_ACL) == 0 || strcmp(bp, "system.posix_acl_access"))
312          count++;
313 #else
314       count++;
315 #endif
316
317       bp = strchr(bp, '\0') + 1;
318    }
319
320    if (count == 0) {
321       free(xattr_list);
322       return bsub_exit_ok;
323    }
324
325    /*
326     * Allocate enough room to hold all extended attributes.
327     * After allocating the storage make sure its empty by zeroing it.
328     */
329    xattr_value_list = (xattr_t *)malloc(count * sizeof(xattr_t));
330    memset((caddr_t)xattr_value_list, 0, count * sizeof(xattr_t));
331
332    /*
333     * Walk the list of extended attributes names and retrieve the data.
334     * We already count the bytes needed for serializing the stream later on.
335     */
336    current_xattr = xattr_value_list;
337    bp = xattr_list;
338    while ((bp - xattr_list) + 1 < xattr_list_len) {
339 #if defined(HAVE_LINUX_OS)
340       if (ff_pkt->flags & FO_ACL && !strcmp(bp, "system.posix_acl_access")) {
341          bp = strchr(bp, '\0') + 1;
342          continue;
343       }
344 #endif
345
346       /*
347        * Each xattr valuepair starts with a magic so we can parse it easier.
348        */
349       current_xattr->magic = XATTR_MAGIC;
350       expected_serialize_len += sizeof(current_xattr->magic);
351
352       /*
353        * Allocate space for storing the name.
354        */
355       current_xattr->name_length = strlen(bp);
356       current_xattr->name = (char *)malloc(current_xattr->name_length);
357       memcpy((caddr_t)current_xattr->name, (caddr_t)bp, current_xattr->name_length);
358
359       expected_serialize_len += sizeof(current_xattr->name_length) + current_xattr->name_length;
360
361       /*
362        * First see how long the value is for the extended attribute.
363        */
364       xattr_value_len = lgetxattr(jcr->last_fname, bp, NULL, 0);
365       if (xattr_value_len < 0) {
366          switch (errno) {
367          case ENOENT:
368             goto bail_out;
369          default:
370             berrno be;
371             Jmsg2(jcr, M_ERROR, 0, _("lgetxattr error on file \"%s\": ERR=%s\n"),
372                jcr->last_fname, be.bstrerror());
373             Dmsg2(100, "lgetxattr error file=%s ERR=%s\n",
374                jcr->last_fname, be.bstrerror());
375             goto bail_out;
376          }
377       }
378
379       /*
380        * Allocate space for storing the value.
381        */
382       current_xattr->value = (char *)malloc(xattr_value_len);
383       memset((caddr_t)current_xattr->value, 0, xattr_value_len);
384
385       xattr_value_len = lgetxattr(jcr->last_fname, bp, current_xattr->value, xattr_value_len);
386       if (xattr_value_len < 0) {
387          switch (errno) {
388          case ENOENT:
389             goto bail_out;
390          default:
391             berrno be;
392             Jmsg2(jcr, M_ERROR, 0, _("lgetxattr error on file \"%s\": ERR=%s\n"),
393                jcr->last_fname, be.bstrerror());
394             Dmsg2(100, "lgetxattr error file=%s ERR=%s\n",
395                jcr->last_fname, be.bstrerror());
396             goto bail_out;
397          }
398       }
399
400       /*
401        * Store the actual length of the value.
402        */
403       current_xattr->value_length = xattr_value_len;
404       expected_serialize_len += sizeof(current_xattr->value_length) + current_xattr->value_length;
405
406       /*
407        * Protect ourself against things getting out of hand.
408        */
409       if (expected_serialize_len >= MAX_XATTR_STREAM) {
410          Jmsg2(jcr, M_ERROR, 0, _("Xattr stream on file \"%s\" exceeds maximum size of %d bytes\n"),
411             jcr->last_fname, MAX_XATTR_STREAM);
412          goto bail_out;
413       }
414       
415       /*
416        * Next attribute.
417        */
418       current_xattr++;
419       bp = strchr(bp, '\0') + 1;
420    }
421
422    /*
423     * Serialize the datastream.
424     */
425    if (serialize_xattr_stream(jcr, expected_serialize_len, xattr_value_list) < expected_serialize_len) {
426       Jmsg1(jcr, M_ERROR, 0, _("Failed to serialize extended attributes on file \"%s\"\n"),
427          jcr->last_fname);
428       Dmsg1(100, "Failed to serialize extended attributes on file \"%s\"\n",
429          jcr->last_fname);
430       goto bail_out;
431    }
432
433    xattr_drop_internal_table(xattr_value_list);
434    free(xattr_list);
435
436    /*
437     * Send the datastream to the SD.
438     */
439    return send_xattr_stream(jcr, default_stream);
440
441 bail_out:
442    xattr_drop_internal_table(xattr_value_list);
443    free(xattr_list);
444    return bsub_exit_nok;
445 }
446
447 static bsub_exit_code generic_xattr_parse_streams(JCR *jcr, int stream)
448 {
449    unser_declare;
450    xattr_t current_xattr;
451    bsub_exit_code retval = bsub_exit_nok;
452
453    /*
454     * Parse the stream and perform the setxattr calls on the file.
455     *
456     * Start unserializing the data. We keep on looping while we have not
457     * unserialized all bytes in the stream.
458     */
459    unser_begin(jcr->xattr_data, jcr->xattr_data_len);
460    while (unser_length(jcr->xattr_data) < jcr->xattr_data_len) {
461       /*
462        * First make sure the magic is present. This way we can easily catch corruption.
463        * Any missing MAGIC is fatal we do NOT try to continue.
464        */
465       unser_uint32(current_xattr.magic);
466       if (current_xattr.magic != XATTR_MAGIC) {
467          Jmsg1(jcr, M_ERROR, 0, _("Illegal xattr stream, no XATTR_MAGIC on file \"%s\"\n"),
468             jcr->last_fname);
469          Dmsg1(100, "Illegal xattr stream, no XATTR_MAGIC on file \"%s\"\n",
470             jcr->last_fname);
471          return bsub_exit_nok;
472       }
473
474       /*
475        * Decode the valuepair. First decode the length of the name.
476        */
477       unser_uint32(current_xattr.name_length);
478       
479       /*
480        * Allocate room for the name and decode its content.
481        */
482       current_xattr.name = (char *)malloc(current_xattr.name_length + 1);
483       unser_bytes(current_xattr.name, current_xattr.name_length);
484
485       /*
486        * The xattr_name needs to be null terminated for lsetxattr.
487        */
488       current_xattr.name[current_xattr.name_length] = '\0';
489
490       /*
491        * Decode the value length.
492        */
493       unser_uint32(current_xattr.value_length);
494
495       /*
496        * Allocate room for the value and decode its content.
497        */
498       current_xattr.value = (char *)malloc(current_xattr.value_length);
499       unser_bytes(current_xattr.value, current_xattr.value_length);
500
501       /*
502        * Try to set the extended attribute on the file.
503        * If we fail to set this attribute we flag the error but its not fatal,
504        * we try to restore the other extended attributes too.
505        */
506       if (lsetxattr(jcr->last_fname, current_xattr.name, current_xattr.value,
507          switch (errno) {
508          case ENOENT:
509             break;
510          default:
511             current_xattr.value_length, 0) != 0) {
512             berrno be;
513             Jmsg2(jcr, M_ERROR, 0, _("lsetxattr error on file \"%s\": ERR=%s\n"),
514                jcr->last_fname, be.bstrerror());
515             Dmsg2(100, "lsetxattr error file=%s ERR=%s\n",
516                jcr->last_fname, be.bstrerror());
517             break;
518          }
519       }
520
521       /*
522        * Free the temporary buffers.
523        */
524       free(current_xattr.name);
525       free(current_xattr.value);
526    }
527
528    unser_end(jcr->xattr_data, jcr->xattr_data_len);
529    return retval;
530 }
531
532 /*
533  * For all these os-es setup the build and parse function pointer to the generic functions.
534  */
535 static bsub_exit_code (*os_build_xattr_streams)(JCR *jcr, FF_PKT *ff_pkt, int default_stream) = generic_xattr_build_streams;
536 static bsub_exit_code (*os_parse_xattr_streams)(JCR *jcr, int stream) = generic_xattr_parse_streams;
537
538 #elif defined(HAVE_SUN_OS)
539 /*
540  * Solaris extended attributes were introduced in Solaris 9
541  * by PSARC 1999/209
542  *
543  * Solaris extensible attributes were introduced in OpenSolaris
544  * by PSARC 2007/315 Solaris extensible attributes are also
545  * sometimes called extended system attributes.
546  *
547  * man fsattr(5) on Solaris gives a wealth of info. The most
548  * important bits are:
549  *
550  * Attributes are logically supported as files within the  file
551  * system.   The  file  system  is  therefore augmented with an
552  * orthogonal name space of file attributes. Any file  (includ-
553  * ing  attribute files) can have an arbitrarily deep attribute
554  * tree associated with it. Attribute values  are  accessed  by
555  * file descriptors obtained through a special attribute inter-
556  * face.  This logical view of "attributes as files" allows the
557  * leveraging  of  existing file system interface functionality
558  * to support the construction, deletion, and  manipulation  of
559  * attributes.
560  *
561  * The special files  "."  and  ".."  retain  their  accustomed
562  * semantics within the attribute hierarchy.  The "." attribute
563  * file refers to the current directory and the ".."  attribute
564  * file  refers to the parent directory.  The unnamed directory
565  * at the head of each attribute tree is considered the "child"
566  * of  the  file it is associated with and the ".." file refers
567  * to the associated file.  For  any  non-directory  file  with
568  * attributes,  the  ".." entry in the unnamed directory refers
569  * to a file that is not a directory.
570  *
571  * Conceptually, the attribute model is fully general. Extended
572  * attributes  can  be  any  type of file (doors, links, direc-
573  * tories, and so forth) and can even have their own attributes
574  * (fully  recursive).   As a result, the attributes associated
575  * with a file could be an arbitrarily deep directory hierarchy
576  * where each attribute could have an equally complex attribute
577  * tree associated with it.  Not all implementations  are  able
578  * to,  or  want to, support the full model. Implementation are
579  * therefore permitted to reject operations that are  not  sup-
580  * ported.   For  example,  the implementation for the UFS file
581  * system allows only regular files as attributes (for example,
582  * no sub-directories) and rejects attempts to place attributes
583  * on attributes.
584  *
585  * The following list details the operations that are  rejected
586  * in the current implementation:
587  *
588  * link                     Any attempt to create links between
589  *                          attribute  and  non-attribute space
590  *                          is rejected  to  prevent  security-
591  *                          related   or   otherwise  sensitive
592  *                          attributes from being exposed,  and
593  *                          therefore  manipulable,  as regular
594  *                          files.
595  *
596  * rename                   Any  attempt  to   rename   between
597  *                          attribute  and  non-attribute space
598  *                          is rejected to prevent  an  already
599  *                          linked  file from being renamed and
600  *                          thereby circumventing the link res-
601  *                          triction above.
602  *
603  * mkdir, symlink, mknod    Any  attempt  to  create  a   "non-
604  *                          regular" file in attribute space is
605  *                          rejected to reduce the  functional-
606  *                          ity,  and  therefore  exposure  and
607  *                          risk, of  the  initial  implementa-
608  *                          tion.
609  *
610  * The entire available name space has been allocated to  "gen-
611  * eral use" to bring the implementation in line with the NFSv4
612  * draft standard [NFSv4]. That standard defines "named  attri-
613  * butes"  (equivalent  to Solaris Extended Attributes) with no
614  * naming restrictions.  All Sun  applications  making  use  of
615  * opaque extended attributes will use the prefix "SUNW".
616  *
617  */
618 #ifdef HAVE_SYS_ATTR_H
619 #include <sys/attr.h>
620 #endif
621
622 #ifdef HAVE_ATTR_H
623 #include <attr.h>
624 #endif
625
626 #ifdef HAVE_SYS_NVPAIR_H
627 #include <sys/nvpair.h>
628 #endif
629
630 #ifdef HAVE_SYS_ACL_H
631 #include <sys/acl.h>
632 #endif
633
634 /*
635  * Number of xattr streams this OS supports and an array with integers with the actual stream numbers.
636  */
637 #if defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED)
638 static int os_default_xattr_streams[2] = { STREAM_XATTR_SOLARIS, STREAM_XATTR_SOLARIS_SYS};
639 #else
640 static int os_default_xattr_streams[1] = { STREAM_XATTR_SOLARIS };
641 #endif /* defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED) */
642
643 /*
644  * This is the count of xattrs saved on a certain file, it gets reset
645  * on each new file processed and is used to see if we need to send
646  * the hidden xattr dir data. We only send that data when we encounter
647  * an other xattr on the file.
648  */
649 static int nr_xattr_saved = 0;
650 static char toplevel_hidden_dir_xattr_data[MAXSTRING];
651 static int toplevel_hidden_dir_xattr_data_len;
652
653 /*
654  * This code creates a temporary cache with entries for each xattr which has
655  * a link count > 1 (which indicates it has one or more hard linked counterpart(s))
656  */
657 static alist *xattr_link_cache = NULL;
658
659 static struct xattr_link_cache_entry *find_xattr_link_cache_entry(ino_t inum)
660 {
661    xattr_link_cache_entry_t *ptr;
662
663    foreach_alist(ptr, xattr_link_cache) {
664       if (ptr && ptr->inum == inum) {
665          return ptr;
666       }
667    }
668    return NULL;
669 }
670
671 static void add_xattr_link_cache_entry(ino_t inum, char *target)
672 {
673    xattr_link_cache_entry_t *ptr;
674
675    ptr = (xattr_link_cache_entry_t *)malloc(sizeof(struct xattr_link_cache_entry));
676    memset((caddr_t)ptr, 0, sizeof(struct xattr_link_cache_entry));
677    ptr->inum = inum;
678    strncpy(ptr->target, target, sizeof(ptr->target));
679    xattr_link_cache->append(ptr);
680 }
681
682 #if defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED)
683 /*
684  * This function returns true if a non default extended system attribute
685  * list is associated with fd and returns false when an error has occured
686  * or when only extended system attributes other than archive,
687  * av_modified or crtime are set.
688  *
689  * The function returns true for the following cases:
690  *
691  * - any extended system attribute other than the default attributes
692  *   ('archive', 'av_modified' and 'crtime') is set
693  * - nvlist has NULL name string
694  * - nvpair has data type of 'nvlist'
695  * - default data type.
696  */
697 static bool solaris_has_non_transient_extensible_attributes(int fd)
698 {
699    boolean_t value;
700    data_type_t type;
701    nvlist_t *response;
702    nvpair_t *pair;
703    f_attr_t fattr;
704    char *name;
705    bool retval = false;
706
707    if (fgetattr(fd, XATTR_VIEW_READWRITE, &response) != 0) {
708       return false;
709    }
710
711    pair = NULL;
712    while ((pair = nvlist_next_nvpair(response, pair)) != NULL) {
713       name = nvpair_name(pair);
714
715       if (name != NULL) {
716          fattr = name_to_attr(name);
717       } else {
718          retval = true;
719          goto cleanup;
720       }
721
722       type = nvpair_type(pair);
723       switch (type) {
724       case DATA_TYPE_BOOLEAN_VALUE:
725          if (nvpair_value_boolean_value(pair, &value) != 0) {
726             continue;
727          }
728          if (value && fattr != F_ARCHIVE &&
729                       fattr != F_AV_MODIFIED) {
730             retval = true;
731             goto cleanup;
732          }
733          break;
734       case DATA_TYPE_UINT64_ARRAY:
735          if (fattr != F_CRTIME) {
736             retval = true;
737             goto cleanup;
738          }
739          break;
740       case DATA_TYPE_NVLIST:
741       default:
742          retval = true;
743          goto cleanup;
744       }
745    }
746
747 cleanup:
748    if (response != NULL) {
749       nvlist_free(response);
750    }
751    return retval;
752 }
753 #endif /* HAVE_SYS_NVPAIR_H && _PC_SATTR_ENABLED */
754
755 #if defined(HAVE_ACL) && !defined(HAVE_EXTENDED_ACL)
756 /*
757  * See if an acl is a trivial one (e.g. just the stat bits encoded as acl.)
758  * There is no need to store those acls as we already store the stat bits too.
759  */
760 static bool acl_is_trivial(int count, aclent_t *entries)
761 {
762    int n;
763    aclent_t *ace;
764
765    for (n = 0; n < count; n++) {
766       ace = &entries[n];
767       if (!(ace->a_type == USER_OBJ ||
768             ace->a_type == GROUP_OBJ ||
769             ace->a_type == OTHER_OBJ ||
770             ace->a_type == CLASS_OBJ))
771         return false;
772    }
773    return true;
774 }
775 #endif /* HAVE_ACL && !HAVE_EXTENDED_ACL */
776
777 static bsub_exit_code solaris_save_xattr_acl(JCR *jcr, int fd, const char *attrname, char **acl_text)
778 {
779 #ifdef HAVE_ACL
780 #ifdef HAVE_EXTENDED_ACL
781    int flags;
782    acl_t *aclp = NULL;
783
784    /*
785     * See if this attribute has an ACL
786     */
787    if ((fd != -1 && fpathconf(fd, _PC_ACL_ENABLED) > 0) ||
788        pathconf(attrname, _PC_ACL_ENABLED) > 0) {
789       /*
790        * See if there is a non trivial acl on the file.
791        */
792       if ((fd != -1 && facl_get(fd, ACL_NO_TRIVIAL, &aclp) != 0) ||
793            acl_get(attrname, ACL_NO_TRIVIAL, &aclp) != 0) {
794          switch (errno) {
795          case ENOENT:
796             return bsub_exit_nok;
797          default:
798             berrno be;
799             Jmsg3(jcr, M_ERROR, 0, _("Unable to get acl on xattr %s on file \"%s\": ERR=%s\n"),
800                attrname, jcr->last_fname, be.bstrerror());
801             Dmsg3(100, "facl_get/acl_get of xattr %s on \"%s\" failed: ERR=%s\n",
802                attrname, jcr->last_fname, be.bstrerror());
803             return bsub_exit_nok;
804          }
805       }
806
807       if (aclp != NULL) {
808 #if defined(ACL_SID_FMT)
809          /*
810           * New format flag added in newer Solaris versions.
811           */
812          flags = ACL_APPEND_ID | ACL_COMPACT_FMT | ACL_SID_FMT;
813 #else
814          flags = ACL_APPEND_ID | ACL_COMPACT_FMT;
815 #endif /* ACL_SID_FMT */
816
817          *acl_text = acl_totext(aclp, flags);
818          acl_free(aclp);
819       } else {
820          *acl_text = NULL;
821       }
822    } else {
823       *acl_text = NULL;
824    }
825    return bsub_exit_ok;
826 #else /* HAVE_EXTENDED_ACL */
827    int n;
828    aclent_t *acls = NULL;
829
830    /*
831     * See if this attribute has an ACL
832     */
833    if (fd != -1) {
834       n = facl(fd, GETACLCNT, 0, NULL);
835    } else {
836       n = acl(attrname, GETACLCNT, 0, NULL);
837    }
838
839    if (n >= MIN_ACL_ENTRIES) {
840       acls = (aclent_t *)malloc(n * sizeof(aclent_t));
841       if ((fd != -1 && facl(fd, GETACL, n, acls) != n) ||
842           acl(attrname, GETACL, n, acls) != n) {
843          switch (errno) {
844          case ENOENT:
845             free(acls);
846             return bsub_exit_nok;
847          default:
848             berrno be;
849             Jmsg3(jcr, M_ERROR, 0, _("Unable to get acl on xattr %s on file \"%s\": ERR=%s\n"),
850                attrname, jcr->last_fname, be.bstrerror());
851             Dmsg3(100, "facl/acl of xattr %s on \"%s\" failed: ERR=%s\n",
852                attrname, jcr->last_fname, be.bstrerror());
853             free(acls);
854             return bsub_exit_nok;
855          }
856       }
857
858       /*
859        * See if there is a non trivial acl on the file.
860        */
861       if (!acl_is_trivial(n, acls)) {
862          if ((*acl_text = acltotext(acls, n)) == NULL) {
863             berrno be;
864             Jmsg3(jcr, M_ERROR, 0, _("Unable to get acl text on xattr %s on file \"%s\": ERR=%s\n"),
865                attrname, jcr->last_fname, be.bstrerror());
866             Dmsg3(100, "acltotext of xattr %s on \"%s\" failed: ERR=%s\n",
867                attrname, jcr->last_fname, be.bstrerror());
868             free(acls);
869             return bsub_exit_nok;
870          }
871       } else {
872          *acl_text = NULL;
873       }
874
875      free(acls);
876    } else {
877       *acl_text = NULL;
878    }
879    return bsub_exit_ok;
880 #endif /* HAVE_EXTENDED_ACL */
881
882 #else /* HAVE_ACL */
883    return bsub_exit_ok;
884 #endif /* HAVE_ACL */
885 }
886
887 /*
888  * Forward declaration for recursive function call.
889  */
890 static bsub_exit_code solaris_save_xattrs(JCR *jcr, const char *xattr_namespace, const char *attr_parent);
891
892 /*
893  * Save an extended or extensible attribute.
894  * This is stored as an opaque stream of bytes with the following encoding:
895  *
896  * <xattr_name>\0<stat_buffer>\0<acl_string>\0<actual_xattr_data>
897  * 
898  * or for a hardlinked or symlinked attribute
899  *
900  * <xattr_name>\0<stat_buffer>\0<xattr_link_source>\0
901  *
902  * xattr_name can be a subpath relative to the file the xattr is on.
903  * stat_buffer is the string representation of the stat struct.
904  * acl_string is an acl text when a non trivial acl is set on the xattr.
905  * actual_xattr_data is the content of the xattr file.
906  */
907 static bsub_exit_code solaris_save_xattr(JCR *jcr, int fd, const char *xattr_namespace,
908                                          const char *attrname, bool toplevel_hidden_dir, int stream)
909 {
910    int cnt;
911    int attrfd = -1;
912    struct stat st;
913    struct xattr_link_cache_entry *xlce;
914    char target_attrname[PATH_MAX];
915    char link_source[PATH_MAX];
916    char *acl_text = NULL;
917    char attribs[MAXSTRING];
918    char buffer[BUFSIZ];
919    bsub_exit_code retval = bsub_exit_nok;
920
921    snprintf(target_attrname, sizeof(target_attrname), "%s%s", xattr_namespace, attrname);
922
923    /*
924     * Get the stats of the extended or extensible attribute.
925     */
926    if (fstatat(fd, attrname, &st, AT_SYMLINK_NOFOLLOW) < 0) {
927       switch (errno) {
928       case ENOENT:
929          goto cleanup;
930       default:
931          berrno be;
932          Jmsg3(jcr, M_ERROR, 0, _("Unable to get status on xattr %s on file \"%s\": ERR=%s\n"),
933             target_attrname, jcr->last_fname, be.bstrerror());
934          Dmsg3(100, "fstatat of xattr %s on \"%s\" failed: ERR=%s\n",
935             target_attrname, jcr->last_fname, be.bstrerror());
936          goto cleanup;
937       }
938    }
939
940    /*
941     * Based on the filetype perform the correct action. We support most filetypes here, more
942     * then the actual implementation on Solaris supports so some code may never get executed
943     * due to limitations in the implementation.
944     */
945    switch (st.st_mode & S_IFMT) {
946    case S_IFIFO:
947    case S_IFCHR:
948    case S_IFBLK:
949       /*
950        * Get any acl on the xattr.
951        */
952       if (solaris_save_xattr_acl(jcr, attrfd, attrname, &acl_text) != bsub_exit_ok)
953          goto cleanup;
954
955       /*
956        * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
957        * Encode the stat struct into an ASCII representation.
958        */
959       encode_stat(attribs, &st, 0, stream);
960       cnt = snprintf(buffer, sizeof(buffer), "%s%c%s%c%s%c",
961                      target_attrname, 0, attribs, 0, (acl_text) ? acl_text : "", 0);
962       break;
963
964    case S_IFDIR:
965       /*
966        * Get any acl on the xattr.
967        */
968       if (solaris_save_xattr_acl(jcr, attrfd, attrname, &acl_text) != bsub_exit_ok)
969          goto cleanup;
970
971       /*
972        * See if this is the toplevel_hidden_dir being saved.
973        */
974       if (toplevel_hidden_dir) {
975          /*
976           * Save the data for later storage when we encounter a real xattr.
977           * Encode the stat struct into an ASCII representation and jump out of the function.
978           */
979          encode_stat(attribs, &st, 0, stream);
980          toplevel_hidden_dir_xattr_data_len = snprintf(toplevel_hidden_dir_xattr_data,
981                                                        sizeof(toplevel_hidden_dir_xattr_data),
982                                                        "%s%c%s%c%s%c",
983                                                        target_attrname, 0, attribs, 0,
984                                                        (acl_text) ? acl_text : "", 0);
985          goto cleanup;
986       } else {
987          /*
988           * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
989           * Encode the stat struct into an ASCII representation.
990           */
991          encode_stat(attribs, &st, 0, stream);
992          cnt = snprintf(buffer, sizeof(buffer),
993                         "%s%c%s%c%s%c",
994                         target_attrname, 0, attribs, 0, (acl_text) ? acl_text : "", 0);
995       }
996       break;
997    case S_IFREG:
998       /*
999        * If this is a hardlinked file check the inode cache for a hit.
1000        */
1001       if (st.st_nlink > 1) {
1002          /*
1003           * See if the cache already knows this inode number.
1004           */
1005          if ((xlce = find_xattr_link_cache_entry(st.st_ino)) != NULL) {
1006             /*
1007              * Generate a xattr encoding with the reference to the target in there.
1008              */
1009             encode_stat(attribs, &st, st.st_ino, stream);
1010             cnt = snprintf(buffer, sizeof(buffer),
1011                            "%s%c%s%c%s%c",
1012                            target_attrname, 0, attribs, 0, xlce->target, 0);
1013             pm_memcpy(jcr->xattr_data, buffer, cnt);
1014             jcr->xattr_data_len = cnt;
1015             retval = send_xattr_stream(jcr, stream);
1016
1017             /*
1018              * For a hard linked file we are ready now, no need to recursively save the attributes.
1019              */
1020             goto cleanup;
1021          }
1022
1023          /*
1024           * Store this hard linked file in the cache.
1025           * Store the name relative to the top level xattr space.
1026           */
1027          add_xattr_link_cache_entry(st.st_ino, target_attrname + 1);
1028       }
1029
1030       /*
1031        * Get any acl on the xattr.
1032        */
1033       if (solaris_save_xattr_acl(jcr, attrfd, attrname, &acl_text) != bsub_exit_ok) {
1034          goto cleanup;
1035       }
1036
1037       /*
1038        * Encode the stat struct into an ASCII representation.
1039        */
1040       encode_stat(attribs, &st, 0, stream);
1041       cnt = snprintf(buffer, sizeof(buffer),
1042                      "%s%c%s%c%s%c",
1043                      target_attrname, 0, attribs, 0, (acl_text) ? acl_text : "", 0);
1044
1045       /*
1046        * Open the extended or extensible attribute file.
1047        */
1048       if ((attrfd = openat(fd, attrname, O_RDONLY)) < 0) {
1049          switch (errno) {
1050          case ENOENT:
1051             goto cleanup;
1052          default:
1053             berrno be;
1054             Jmsg3(jcr, M_ERROR, 0, _("Unable to open xattr %s on \"%s\": ERR=%s\n"),
1055                target_attrname, jcr->last_fname, be.bstrerror());
1056             Dmsg3(100, "openat of xattr %s on \"%s\" failed: ERR=%s\n",
1057                target_attrname, jcr->last_fname, be.bstrerror());
1058             goto cleanup;
1059          }
1060       }
1061       break;
1062
1063    case S_IFLNK:
1064       /*
1065        * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
1066        * Encode the stat struct into an ASCII representation.
1067        */
1068       if (readlink(attrname, link_source, sizeof(link_source)) < 0) {
1069          switch (errno) {
1070          case ENOENT:
1071             goto cleanup;
1072          default:
1073             berrno be;
1074             Jmsg3(jcr, M_ERROR, 0, _("Unable to read symlin %s on \"%s\": ERR=%s\n"),
1075                target_attrname, jcr->last_fname, be.bstrerror());
1076             Dmsg3(100, "readlink of xattr %s on \"%s\" failed: ERR=%s\n",
1077                target_attrname, jcr->last_fname, be.bstrerror());
1078             goto cleanup;
1079          }
1080       }
1081
1082       /*
1083        * Generate a xattr encoding with the reference to the target in there.
1084        */
1085       encode_stat(attribs, &st, st.st_ino, stream);
1086       cnt = snprintf(buffer, sizeof(buffer),
1087                      "%s%c%s%c%s%c",
1088                      target_attrname, 0, attribs, 0, link_source, 0);
1089       pm_memcpy(jcr->xattr_data, buffer, cnt);
1090       jcr->xattr_data_len = cnt;
1091       retval = send_xattr_stream(jcr, stream);
1092
1093       /*
1094        * For a soft linked file we are ready now, no need to recursively save the attributes.
1095        */
1096       goto cleanup;
1097
1098    default:
1099       goto cleanup;
1100    }
1101
1102    /*
1103     * See if this is the first real xattr being saved. If it is save the toplevel_hidden_dir attributes first.
1104     */
1105    if (nr_xattr_saved == 0) {
1106       pm_memcpy(jcr->xattr_data, toplevel_hidden_dir_xattr_data, toplevel_hidden_dir_xattr_data_len);
1107       jcr->xattr_data_len = toplevel_hidden_dir_xattr_data_len;
1108       retval = send_xattr_stream(jcr, STREAM_XATTR_SOLARIS);
1109    }
1110
1111    pm_memcpy(jcr->xattr_data, buffer, cnt);
1112    jcr->xattr_data_len = cnt;
1113
1114    /*
1115     * Only dump the content of regular files.
1116     */
1117    switch (st.st_mode & S_IFMT) {
1118    case S_IFREG:
1119       if (st.st_size > 0) {
1120          /*
1121           * Protect ourself against things getting out of hand.
1122           */
1123          if (st.st_size >= MAX_XATTR_STREAM) {
1124             Jmsg2(jcr, M_ERROR, 0, _("Xattr stream on file \"%s\" exceeds maximum size of %d bytes\n"),
1125                jcr->last_fname, MAX_XATTR_STREAM);
1126             goto cleanup;
1127          }
1128
1129          while ((cnt = read(attrfd, buffer, sizeof(buffer))) > 0) {
1130             jcr->xattr_data = check_pool_memory_size(jcr->xattr_data, jcr->xattr_data_len + cnt);
1131             memcpy(jcr->xattr_data + jcr->xattr_data_len, buffer, cnt);
1132             jcr->xattr_data_len += cnt;
1133          }
1134
1135          if (cnt < 0) {
1136             Jmsg2(jcr, M_ERROR, 0, _("Unable to read content of xattr %s on file \"%s\"\n"),
1137                target_attrname, jcr->last_fname);
1138             Dmsg2(100, "read of data from xattr %s on \"%s\" failed\n",
1139                target_attrname, jcr->last_fname);
1140             goto cleanup;
1141          }
1142       }
1143       break;
1144
1145    default:
1146       break;
1147    }
1148
1149    if (retval) {
1150       retval = send_xattr_stream(jcr, stream);
1151       nr_xattr_saved++;
1152    }
1153
1154    /*
1155     * Recursivly call solaris_save_extended_attributes for archiving the attributes
1156     * available on this extended attribute.
1157     */
1158    if (retval) {
1159       retval = solaris_save_xattrs(jcr, xattr_namespace, attrname);
1160       
1161       /*
1162        * The recursive call could change our working dir so change back to the wanted workdir.
1163        */
1164       if (fchdir(fd) < 0) {
1165          switch (errno) {
1166          case ENOENT:
1167             goto cleanup;
1168          default:
1169             berrno be;
1170             Jmsg2(jcr, M_ERROR, 0, _("Unable to chdir to xattr space of file \"%s\": ERR=%s\n"),
1171                jcr->last_fname, be.bstrerror());
1172             Dmsg3(100, "Unable to fchdir to xattr space of file \"%s\" using fd %d: ERR=%s\n",
1173                jcr->last_fname, fd, be.bstrerror());
1174             goto cleanup;
1175          }
1176       }
1177    }
1178
1179 cleanup:
1180    if (acl_text) {
1181       free(acl_text);
1182    }
1183    if (attrfd != -1) {
1184       close(attrfd);
1185    }
1186    return retval;
1187 }
1188
1189 static bsub_exit_code solaris_save_xattrs(JCR *jcr, const char *xattr_namespace, const char *attr_parent)
1190 {
1191    const char *name;
1192    int fd, filefd = -1, attrdirfd = -1;
1193    DIR *dirp;
1194    struct dirent *dp;
1195    char current_xattr_namespace[PATH_MAX];
1196    bsub_exit_code retval = bsub_exit_nok;
1197  
1198    /*
1199     * Determine what argument to use. Use attr_parent when set
1200     * (recursive call) or jcr->last_fname for first call. Also save
1201     * the current depth of the xattr_space we are in.
1202     */
1203    if (attr_parent) {
1204       name = attr_parent;
1205       if (xattr_namespace) {
1206          snprintf(current_xattr_namespace, sizeof(current_xattr_namespace), "%s%s/",
1207                   xattr_namespace, attr_parent);
1208       } else {
1209          strncpy(current_xattr_namespace, "/", sizeof(current_xattr_namespace));
1210       }
1211    } else {
1212       name = jcr->last_fname;
1213       strncpy(current_xattr_namespace, "/", sizeof(current_xattr_namespace));
1214    }
1215
1216    /*
1217     * Open the file on which to save the xattrs read-only.
1218     */
1219    if ((filefd = open(name, O_RDONLY | O_NONBLOCK)) < 0) {
1220       switch (errno) {
1221       case ENOENT:
1222          goto cleanup;
1223       default:
1224          berrno be;
1225          Jmsg2(jcr, M_ERROR, 0, _("Unable to open file \"%s\": ERR=%s\n"),
1226             jcr->last_fname, be.bstrerror());
1227          Dmsg2(100, "Unable to open file \"%s\": ERR=%s\n",
1228             jcr->last_fname, be.bstrerror());
1229          goto cleanup;
1230       }
1231    }
1232
1233    /*
1234     * Open the xattr naming space.
1235     */
1236    if ((attrdirfd = openat(filefd, ".", O_RDONLY | O_XATTR)) < 0) {
1237       switch (errno) {
1238       case EINVAL:
1239          /*
1240           * Gentile way of the system saying this type of xattr layering is not supported.
1241           * Which is not problem we just forget about this this xattr.
1242           * But as this is not an error we return a positive return value.
1243           */
1244          retval = bsub_exit_ok;
1245          goto cleanup;
1246       case ENOENT:
1247          goto cleanup;
1248       default:
1249          berrno be;
1250          Jmsg3(jcr, M_ERROR, 0, _("Unable to open xattr space %s on file \"%s\": ERR=%s\n"),
1251             name, jcr->last_fname, be.bstrerror());
1252          Dmsg3(100, "Unable to open xattr space %s on file \"%s\": ERR=%s\n",
1253             name, jcr->last_fname, be.bstrerror());
1254          goto cleanup;
1255       }
1256    }
1257
1258   /*
1259    * We need to change into the attribute directory to determine if each of the
1260    * attributes should be saved.
1261    */
1262    if (fchdir(attrdirfd) < 0) {
1263       berrno be;
1264       Jmsg2(jcr, M_ERROR, 0, _("Unable to chdir to xattr space on file \"%s\": ERR=%s\n"),
1265          jcr->last_fname, be.bstrerror());
1266       Dmsg3(100, "Unable to fchdir to xattr space on file \"%s\" using fd %d: ERR=%s\n",
1267          jcr->last_fname, attrdirfd, be.bstrerror());
1268       goto cleanup;
1269    }
1270
1271    /*
1272     * Save the data of the toplevel xattr hidden_dir. We save this one before anything
1273     * else because the readdir returns "." entry after the extensible attr entry.
1274     * And as we want this entry before anything else we better just save its data.
1275     */
1276    if (!attr_parent)
1277       solaris_save_xattr(jcr, attrdirfd, current_xattr_namespace, ".",
1278                             true, STREAM_XATTR_SOLARIS);
1279
1280    if ((fd = dup(attrdirfd)) == -1 ||
1281        (dirp = fdopendir(fd)) == (DIR *)NULL) {
1282       berrno be;
1283       Jmsg2(jcr, M_ERROR, 0, _("Unable to list the xattr space on file \"%s\": ERR=%s\n"),
1284          jcr->last_fname, be.bstrerror());
1285       Dmsg3(100, "Unable to fdopendir xattr space on file \"%s\" using fd %d: ERR=%s\n",
1286          jcr->last_fname, fd, be.bstrerror());
1287
1288       goto cleanup;
1289    }
1290
1291    /*
1292     * Walk the namespace.
1293     */
1294    while (dp = readdir(dirp)) {
1295       /*
1296        * Skip only the toplevel . dir.
1297        */
1298       if (!attr_parent && !strcmp(dp->d_name, "."))
1299          continue;
1300
1301       /*
1302        * Skip all .. directories
1303        */
1304       if (!strcmp(dp->d_name, ".."))
1305          continue;
1306
1307       Dmsg3(400, "processing extended attribute %s%s on file \"%s\"\n",
1308          current_xattr_namespace, dp->d_name, jcr->last_fname);
1309
1310 #if defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED)
1311       /*
1312        * We are not interested in read-only extensible attributes.
1313        */
1314       if (!strcmp(dp->d_name, VIEW_READONLY)) {
1315          Dmsg3(400, "Skipping readonly extensible attributes %s%s on file \"%s\"\n",
1316             current_xattr_namespace, dp->d_name, jcr->last_fname);
1317
1318          continue;
1319       }
1320
1321       /*
1322        * We are only interested in read-write extensible attributes
1323        * when they contain non-transient values.
1324        */
1325       if (!strcmp(dp->d_name, VIEW_READWRITE)) {
1326          /*
1327           * Determine if there are non-transient system attributes at the toplevel.
1328           * We need to provide a fd to the open file.
1329           */
1330          if (!solaris_has_non_transient_extensible_attributes(filefd)) {
1331             Dmsg3(400, "Skipping transient extensible attributes %s%s on file \"%s\"\n",
1332                current_xattr_namespace, dp->d_name, jcr->last_fname);
1333             continue;
1334          }
1335
1336          /*
1337           * Save the xattr.
1338           */
1339          solaris_save_xattr(jcr, attrdirfd, current_xattr_namespace, dp->d_name,
1340                                false, STREAM_XATTR_SOLARIS_SYS);
1341          continue;
1342       }
1343 #endif /* HAVE_SYS_NVPAIR_H && _PC_SATTR_ENABLED */
1344
1345       /*
1346        * Save the xattr.
1347        */
1348       solaris_save_xattr(jcr, attrdirfd, current_xattr_namespace, dp->d_name,
1349                             false, STREAM_XATTR_SOLARIS);
1350    }
1351
1352    closedir(dirp);
1353    retval = bsub_exit_ok;
1354
1355 cleanup:
1356    if (attrdirfd != -1)
1357       close(attrdirfd);
1358    if (filefd != -1)
1359       close(filefd);
1360    return retval;
1361 }
1362
1363 #ifdef HAVE_ACL
1364 static bsub_exit_code solaris_restore_xattr_acl(JCR *jcr, int fd, const char *attrname, char *acl_text)
1365 {
1366 #ifdef HAVE_EXTENDED_ACL
1367    int error;
1368    acl_t *aclp = NULL;
1369
1370    if ((error = acl_fromtext(acl_text, &aclp)) != 0) {
1371       Jmsg1(jcr, M_ERROR, 0, _("Unable to convert acl from text on file \"%s\"\n"),
1372             jcr->last_fname);
1373       return bsub_exit_nok;
1374    }
1375
1376    if ((fd != -1 && facl_set(fd, aclp) != 0) ||
1377         acl_set(attrname, aclp) != 0) {
1378       berrno be;
1379       Jmsg3(jcr, M_ERROR, 0, _("Unable to restore acl of xattr %s on file \"%s\": ERR=%s\n"),
1380          attrname, jcr->last_fname, be.bstrerror());
1381       Dmsg3(100, "Unable to restore acl of xattr %s on file \"%s\": ERR=%s\n",
1382          attrname, jcr->last_fname, be.bstrerror());
1383       return bsub_exit_nok;
1384    }
1385
1386    if (aclp) {
1387       acl_free(aclp);
1388    }
1389    return bsub_exit_ok;
1390
1391 #else /* HAVE_EXTENDED_ACL */
1392    int n;
1393    aclent_t *acls = NULL;
1394
1395    acls = aclfromtext(acl_text, &n);
1396    if (!acls) {
1397       if ((fd != -1 && facl(fd, SETACL, n, acls) != 0) ||
1398            acl(attrname, SETACL, n, acls) != 0) {
1399          berrno be;
1400          Jmsg3(jcr, M_ERROR, 0, _("Unable to restore acl of xattr %s on file \"%s\": ERR=%s\n"),
1401             attrname, jcr->last_fname, be.bstrerror());
1402          Dmsg3(100, "Unable to restore acl of xattr %s on file \"%s\": ERR=%s\n",
1403             attrname, jcr->last_fname, be.bstrerror());
1404          return bsub_exit_nok;
1405       }
1406    }
1407
1408    if (acls) {
1409       free(acls);
1410    }
1411    return bsub_exit_ok;
1412
1413 #endif /* HAVE_EXTENDED_ACL */
1414
1415 }
1416 #endif /* HAVE_ACL */
1417
1418 static bsub_exit_code solaris_restore_xattrs(JCR *jcr, bool is_extensible)
1419 {
1420    int fd, filefd = -1, attrdirfd = -1, attrfd = -1;
1421    int used_bytes, total_bytes, cnt;
1422    char *bp, *target_attrname, *attribs;
1423    char *linked_target = NULL;
1424    char *acl_text = NULL;
1425    char *data = NULL;
1426    int32_t inum;
1427    struct stat st;
1428    struct timeval times[2];
1429    bsub_exit_code retval = bsub_exit_nok;
1430
1431    /*
1432     * Parse the xattr stream. First the part that is the same for all xattrs.
1433     */
1434    used_bytes = 0;
1435    total_bytes = jcr->xattr_data_len;
1436
1437    /*
1438     * The name of the target xattr has a leading / we are not interested
1439     * in that so skip it when decoding the string. We always start a the /
1440     * of the xattr space anyway.
1441     */
1442    target_attrname = jcr->xattr_data + 1;
1443    if ((bp = strchr(target_attrname, '\0')) == (char *)NULL ||
1444        (used_bytes = (bp - jcr->xattr_data)) >= (total_bytes - 1)) {
1445       goto parse_error;
1446    }
1447    attribs = ++bp;
1448
1449    /*
1450     * Open the file on which to restore the xattrs read-only.
1451     */
1452    if ((filefd = open(jcr->last_fname, O_RDONLY | O_NONBLOCK)) < 0) {
1453       berrno be;
1454       Jmsg2(jcr, M_ERROR, 0, _("Unable to open file \"%s\": ERR=%s\n"),
1455          jcr->last_fname, be.bstrerror());
1456       Dmsg2(100, "Unable to open file \"%s\": ERR=%s\n",
1457          jcr->last_fname, be.bstrerror());
1458       goto cleanup;
1459    }
1460
1461    /*
1462     * Open the xattr naming space and make it the current working dir.
1463     */
1464    if ((attrdirfd = openat(filefd, ".", O_RDONLY | O_XATTR)) < 0) {
1465       berrno be;
1466       Jmsg2(jcr, M_ERROR, 0, _("Unable to open xattr space on file \"%s\": ERR=%s\n"),
1467          jcr->last_fname, be.bstrerror());
1468       Dmsg2(100, "Unable to open xattr space on file \"%s\": ERR=%s\n",
1469          jcr->last_fname, be.bstrerror());
1470       goto cleanup;
1471    }
1472
1473    if (fchdir(attrdirfd) < 0) {
1474       berrno be;
1475       Jmsg2(jcr, M_ERROR, 0, _("Unable to chdir to xattr space on file \"%s\": ERR=%s\n"),
1476          jcr->last_fname, be.bstrerror());
1477       Dmsg3(100, "Unable to fchdir to xattr space on file \"%s\" using fd %d: ERR=%s\n",
1478          jcr->last_fname, attrdirfd, be.bstrerror());
1479       goto cleanup;
1480    }
1481
1482    /*
1483     * Try to open the correct xattr subdir based on the target_attrname given.
1484     * e.g. check if its a subdir attrname. Each / in the string makes us go
1485     * one level deeper.
1486     */
1487    while ((bp = strchr(target_attrname, '/')) != (char *)NULL) {
1488       *bp = '\0';
1489
1490       if ((fd = open(target_attrname, O_RDONLY | O_NONBLOCK)) < 0) {
1491          berrno be;
1492          Jmsg3(jcr, M_ERROR, 0, _("Unable to open xattr %s on file \"%s\": ERR=%s\n"),
1493             target_attrname, jcr->last_fname, be.bstrerror());
1494          Dmsg3(100, "Unable to open xattr %s on file \"%s\": ERR=%s\n",
1495             target_attrname, jcr->last_fname, be.bstrerror());
1496          goto cleanup;
1497       }
1498
1499       close(filefd);
1500       filefd = fd;
1501
1502       /*
1503        * Open the xattr naming space.
1504        */
1505       if ((fd = openat(filefd, ".", O_RDONLY | O_XATTR)) < 0) {
1506          berrno be;
1507          Jmsg3(jcr, M_ERROR, 0, _("Unable to open xattr space %s on file \"%s\": ERR=%s\n"),
1508             target_attrname, jcr->last_fname, be.bstrerror());
1509          Dmsg3(100, "Unable to open xattr space %s on file \"%s\": ERR=%s\n",
1510             target_attrname, jcr->last_fname, be.bstrerror());
1511          goto cleanup;
1512       }
1513
1514       close(attrdirfd);
1515       attrdirfd = fd;
1516
1517       /*
1518        * Make the xattr space our current workingdir.
1519        */
1520       if (fchdir(attrdirfd) < 0) {
1521          berrno be;
1522          Jmsg3(jcr, M_ERROR, 0, _("Unable to chdir to xattr space %s on file \"%s\": ERR=%s\n"),
1523             target_attrname, jcr->last_fname, be.bstrerror());
1524          Dmsg4(100, "Unable to fchdir to xattr space %s on file \"%s\" using fd %d: ERR=%s\n",
1525             target_attrname, jcr->last_fname, attrdirfd, be.bstrerror());
1526          goto cleanup;
1527       }
1528
1529       target_attrname = ++bp;
1530    }
1531
1532    /*
1533     * Decode the attributes from the stream.
1534     */
1535    decode_stat(attribs, &st, &inum);
1536
1537    /*
1538     * Decode the next field (acl_text).
1539     */
1540    if ((bp = strchr(attribs, '\0')) == (char *)NULL ||
1541        (used_bytes = (bp - jcr->xattr_data)) >= (total_bytes - 1)) {
1542       goto parse_error;
1543    }
1544    acl_text = ++bp;
1545
1546    /*
1547     * Based on the filetype perform the correct action. We support most filetypes here, more
1548     * then the actual implementation on Solaris supports so some code may never get executed
1549     * due to limitations in the implementation.
1550     */
1551    switch (st.st_mode & S_IFMT) {
1552    case S_IFIFO:
1553       /*
1554        * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
1555        */
1556       unlinkat(attrdirfd, target_attrname, 0);
1557       if (mkfifo(target_attrname, st.st_mode) < 0) {
1558          berrno be;
1559          Jmsg3(jcr, M_ERROR, 0, _("Unable to mkfifo xattr %s on file \"%s\": ERR=%s\n"),
1560             target_attrname, jcr->last_fname, be.bstrerror());
1561          Dmsg3(100, "Unable to mkfifo xattr %s on file \"%s\": ERR=%s\n",
1562             target_attrname,  jcr->last_fname, be.bstrerror());
1563          goto cleanup;
1564       }
1565       break;
1566    case S_IFCHR:
1567    case S_IFBLK:
1568       /*
1569        * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
1570        */
1571       unlinkat(attrdirfd, target_attrname, 0);
1572       if (mknod(target_attrname, st.st_mode, st.st_rdev) < 0) {
1573          berrno be;
1574          Jmsg3(jcr, M_ERROR, 0, _("Unable to mknod xattr %s on file \"%s\": ERR=%s\n"),
1575             target_attrname, jcr->last_fname, be.bstrerror());
1576          Dmsg3(100, "Unable to mknod xattr %s on file \"%s\": ERR=%s\n",
1577             target_attrname,  jcr->last_fname, be.bstrerror());
1578          goto cleanup;
1579       }
1580       break;
1581    case S_IFDIR:
1582       /*
1583        * If its not the hidden_dir create the entry.
1584        * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
1585        */
1586       if (strcmp(target_attrname, ".")) {
1587          unlinkat(attrdirfd, target_attrname, AT_REMOVEDIR);
1588          if (mkdir(target_attrname, st.st_mode) < 0) {
1589             berrno be;
1590             Jmsg3(jcr, M_WARNING, 0, _("Unable to mkdir xattr %s on file \"%s\": ERR=%s\n"),
1591                target_attrname, jcr->last_fname, be.bstrerror());
1592             Dmsg3(100, "Unable to mkdir xattr %s on file \"%s\": ERR=%s\n",
1593                target_attrname,  jcr->last_fname, be.bstrerror());
1594             goto cleanup;
1595          }
1596       }
1597       break;
1598    case S_IFREG:
1599       /*
1600        * See if this is a hard linked file. e.g. inum != 0
1601        */
1602       if (inum != 0) {
1603          linked_target = bp;
1604
1605          unlinkat(attrdirfd, target_attrname, 0);
1606          if (link(linked_target, target_attrname) < 0) {
1607             berrno be;
1608             Jmsg4(jcr, M_ERROR, 0, _("Unable to link xattr %s to %s on file \"%s\": ERR=%s\n"),
1609                target_attrname, linked_target, jcr->last_fname, be.bstrerror());
1610             Dmsg4(100, "Unable to link xattr %s to %s on file \"%s\": ERR=%s\n",
1611                target_attrname, linked_target, jcr->last_fname, be.bstrerror());
1612             goto cleanup;
1613          }
1614
1615          /*
1616           * Successfully restored xattr.
1617           */
1618          retval = bsub_exit_ok;
1619          goto cleanup;
1620       } else {
1621          if ((bp = strchr(acl_text, '\0')) == (char *)NULL ||
1622              (used_bytes = (bp - jcr->xattr_data)) >= total_bytes) {
1623             goto parse_error;
1624          }
1625
1626          if (used_bytes < (total_bytes - 1))
1627             data = ++bp;
1628
1629          /*
1630           * Restore the actual xattr.
1631           */
1632          if (!is_extensible) {
1633             unlinkat(attrdirfd, target_attrname, 0);
1634          }
1635
1636          if ((attrfd = openat(attrdirfd, target_attrname, O_RDWR | O_CREAT | O_TRUNC, st.st_mode)) < 0) {
1637             berrno be;
1638             Jmsg3(jcr, M_ERROR, 0, _("Unable to open xattr %s on file \"%s\": ERR=%s\n"),
1639                target_attrname, jcr->last_fname, be.bstrerror());
1640             Dmsg3(100, "Unable to open xattr %s on file \"%s\": ERR=%s\n",
1641                target_attrname, jcr->last_fname, be.bstrerror());
1642             goto cleanup;
1643          }
1644       }
1645
1646       /*
1647        * Restore the actual data.
1648        */
1649       if (st.st_size > 0) {
1650          used_bytes = (data - jcr->xattr_data);
1651          cnt = total_bytes - used_bytes;
1652
1653          /*
1654           * Do a sanity check, the st.st_size should be the same as the number of bytes
1655           * we have available as data of the stream.
1656           */
1657          if (cnt != st.st_size) {
1658             Jmsg2(jcr, M_ERROR, 0, _("Unable to restore data of xattr %s on file \"%s\": Not all data available in xattr stream\n"),
1659                target_attrname, jcr->last_fname);
1660             Dmsg2(100, "Unable to restore data of xattr %s on file \"%s\": Not all data available in xattr stream\n",
1661                target_attrname, jcr->last_fname);
1662             goto cleanup;
1663          }
1664
1665          while (cnt > 0) {
1666             cnt = write(attrfd, data, cnt);
1667             if (cnt < 0) {
1668                berrno be;
1669                Jmsg3(jcr, M_ERROR, 0, _("Unable to restore data of xattr %s on file \"%s\": ERR=%s\n"),
1670                   target_attrname, jcr->last_fname, be.bstrerror());
1671                Dmsg3(100, "Unable to restore data of xattr %s on file \"%s\": ERR=%s\n",
1672                   target_attrname, jcr->last_fname, be.bstrerror());
1673                goto cleanup;
1674             }
1675
1676             used_bytes += cnt;
1677             data += cnt;
1678             cnt = total_bytes - used_bytes;
1679          }
1680       }
1681       break;
1682    case S_IFLNK:
1683       /*
1684        * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
1685        */
1686       linked_target = bp;
1687
1688       if (symlink(linked_target, target_attrname) < 0) {
1689          berrno be;
1690          Jmsg4(jcr, M_ERROR, 0, _("Unable to symlink xattr %s to %s on file \"%s\": ERR=%s\n"),
1691             target_attrname, linked_target, jcr->last_fname, be.bstrerror());
1692          Dmsg4(100, "Unable to symlink xattr %s to %s on file \"%s\": ERR=%s\n",
1693             target_attrname, linked_target, jcr->last_fname, be.bstrerror());
1694          goto cleanup;
1695       }
1696
1697       /*
1698        * Successfully restored xattr.
1699        */
1700       retval = bsub_exit_ok;
1701       goto cleanup;
1702    default:
1703       goto cleanup;
1704    }
1705
1706    /*
1707     * Restore owner and acl for non extensible attributes.
1708     */
1709    if (!is_extensible) {
1710       if (fchownat(attrdirfd, target_attrname, st.st_uid, st.st_gid, AT_SYMLINK_NOFOLLOW) < 0) {
1711          switch (errno) {
1712          case EINVAL:
1713             /*
1714              * Gentile way of the system saying this type of xattr layering is not supported.
1715              * But as this is not an error we return a positive return value.
1716              */
1717             retval = bsub_exit_ok;
1718             break;
1719          default:
1720             berrno be;
1721             Jmsg3(jcr, M_ERROR, 0, _("Unable to restore owner of xattr %s on file \"%s\": ERR=%s\n"),
1722                target_attrname, jcr->last_fname, be.bstrerror());
1723             Dmsg3(100, "Unable to restore owner of xattr %s on file \"%s\": ERR=%s\n",
1724                target_attrname, jcr->last_fname, be.bstrerror());
1725          }
1726          goto cleanup;
1727       }
1728    }
1729
1730 #ifdef HAVE_ACL
1731    if (acl_text && *acl_text)
1732       if (solaris_restore_xattr_acl(jcr, attrfd, target_attrname, acl_text) != bsub_exit_ok)
1733          goto cleanup;
1734 #endif /* HAVE_ACL */
1735
1736    /*
1737     * For a non extensible attribute restore access and modification time on the xattr.
1738     */
1739    if (!is_extensible) {
1740       times[0].tv_sec = st.st_atime;
1741       times[0].tv_usec = 0;
1742       times[1].tv_sec = st.st_mtime;
1743       times[1].tv_usec = 0;
1744
1745       if (futimesat(attrdirfd, target_attrname, times) < 0) {
1746          berrno be;
1747          Jmsg3(jcr, M_ERROR, 0, _("Unable to restore filetimes of xattr %s on file \"%s\": ERR=%s\n"),
1748             target_attrname, jcr->last_fname, be.bstrerror());
1749          Dmsg3(100, "Unable to restore filetimes of xattr %s on file \"%s\": ERR=%s\n",
1750             target_attrname, jcr->last_fname, be.bstrerror());
1751          goto cleanup;
1752       }
1753    }
1754
1755    /*
1756     * Successfully restored xattr.
1757     */
1758    retval = bsub_exit_ok;
1759    goto cleanup;
1760
1761 parse_error:
1762    Jmsg1(jcr, M_ERROR, 0, _("Illegal xattr stream, failed to parse xattr stream on file \"%s\"\n"),
1763       jcr->last_fname);
1764    Dmsg1(100, "Illegal xattr stream, failed to parse xattr stream on file \"%s\"\n",
1765       jcr->last_fname);
1766
1767 cleanup:
1768    if (attrfd != -1) {
1769       close(attrfd);
1770    }
1771    if (attrdirfd != -1) {
1772       close(attrdirfd);
1773    }
1774    if (filefd != -1) {
1775       close(filefd);
1776    }
1777    return retval;
1778 }
1779
1780 static bsub_exit_code solaris_build_xattr_streams(JCR *jcr, FF_PKT *ff_pkt, int default_stream)
1781 {
1782    char cwd[PATH_MAX];
1783    bsub_exit_code retval = bsub_exit_ok;
1784
1785    /*
1786     * First see if extended attributes or extensible attributes are present.
1787     * If not just pretend things went ok.
1788     */
1789    if (pathconf(jcr->last_fname, _PC_XATTR_EXISTS) > 0) {
1790       nr_xattr_saved = 0;
1791
1792       /*
1793        * As we change the cwd in the save function save the current cwd
1794        * for restore after return from the solaris_save_xattrs function.
1795        */
1796       xattr_link_cache = New(alist(10, not_owned_by_alist));
1797       getcwd(cwd, sizeof(cwd));
1798       retval = solaris_save_xattrs(jcr, NULL, NULL);
1799       chdir(cwd);
1800       delete xattr_link_cache;
1801       xattr_link_cache = NULL;
1802    }
1803    return retval;
1804 }
1805
1806 static bsub_exit_code solaris_parse_xattr_streams(JCR *jcr, int stream)
1807 {
1808    char cwd[PATH_MAX];
1809    bool is_extensible = false;
1810    bsub_exit_code retval;
1811
1812    /*
1813     * First make sure we can restore xattr on the filesystem.
1814     */
1815    switch (stream) {
1816 #if defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED)
1817    case STREAM_XATTR_SOLARIS_SYS:
1818       if (pathconf(jcr->last_fname, _PC_SATTR_ENABLED) <= 0) {
1819          Qmsg1(jcr, M_WARNING, 0,
1820                _("Failed to restore extensible attributes on file \"%s\"\n"),
1821                jcr->last_fname);
1822          Dmsg1(100, "Unable to restore extensible attributes on file \"%s\", filesystem doesn't support this\n",
1823             jcr->last_fname);
1824          return bsub_exit_nok;
1825       }
1826
1827       is_extensible = true;
1828       break;
1829 #endif
1830    case STREAM_XATTR_SOLARIS:
1831       if (pathconf(jcr->last_fname, _PC_XATTR_ENABLED) <= 0) {
1832          Qmsg1(jcr, M_WARNING, 0,
1833                _("Failed to restore extended attributes on file \"%s\"\n"),
1834                jcr->last_fname);
1835          Dmsg1(100, "Unable to restore extended attributes on file \"%s\", filesystem doesn't support this\n",
1836             jcr->last_fname);
1837          return bsub_exit_nok;
1838       }
1839       break;
1840    default:
1841       return bsub_exit_nok;
1842    }
1843
1844    /*
1845     * As we change the cwd in the restore function save the current cwd
1846     * for restore after return from the solaris_restore_xattrs function.
1847     */
1848    getcwd(cwd, sizeof(cwd));
1849    retval = solaris_restore_xattrs(jcr, is_extensible);
1850    chdir(cwd);
1851    return retval;
1852 }
1853
1854
1855 /*
1856  * Function pointers to the build and parse function to use for these xattrs.
1857  */
1858 static bsub_exit_code (*os_build_xattr_streams)(JCR *jcr, FF_PKT *ff_pkt, int default_stream) = solaris_build_xattr_streams;
1859 static bsub_exit_code (*os_parse_xattr_streams)(JCR *jcr, int stream) = solaris_parse_xattr_streams;
1860
1861 #endif /* defined(HAVE_SUN_OS) */
1862
1863 bsub_exit_code build_xattr_streams(JCR *jcr, FF_PKT *ff_pkt)
1864 {
1865    if (os_build_xattr_streams) {
1866       return (*os_build_xattr_streams)(jcr, ff_pkt, os_default_xattr_streams[0]);
1867    }
1868    return bsub_exit_nok;
1869 }
1870
1871 bsub_exit_code parse_xattr_streams(JCR *jcr, int stream)
1872 {
1873    int cnt;
1874
1875    if (os_parse_xattr_streams) {
1876       /*
1877        * See if we can parse this stream, and ifso give it a try.
1878        */
1879       for (cnt = 0; cnt < sizeof(os_default_xattr_streams) / sizeof(int); cnt++) {
1880          if (os_default_xattr_streams[cnt] == stream) {
1881             return (*os_parse_xattr_streams)(jcr, stream);
1882          }
1883       }
1884    }
1885    /*
1886     * Issue a warning and discard the message. But pretend the restore was ok.
1887     */
1888    Jmsg2(jcr, M_WARNING, 0,
1889       _("Can't restore Extended Attributes of %s - incompatible xattr stream encountered - %d\n"),
1890       jcr->last_fname, stream);
1891    return bsub_exit_nok;
1892 }
1893 #endif