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