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