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