]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/filed/xattr.c
No need to flush the members of the xattr link cache as they are not
[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
49 #if !defined(HAVE_XATTR)
50 /*
51  * Entry points when compiled without support for XATTRs or on an unsupported platform.
52  */
53 bxattr_exit_code build_xattr_streams(JCR *jcr, FF_PKT *ff_pkt)
54 {
55    return bxattr_exit_fatal;
56 }
57
58 bxattr_exit_code parse_xattr_streams(JCR *jcr, int stream)
59 {
60    return bxattr_exit_fatal;
61 }
62 #else
63 /*
64  * Send a XATTR stream to the SD.
65  */
66 static bxattr_exit_code send_xattr_stream(JCR *jcr, int stream)
67 {
68    BSOCK *sd = jcr->store_bsock;
69    POOLMEM *msgsave;
70 #ifdef FD_NO_SEND_TEST
71    return bxattr_exit_ok;
72 #endif
73
74    /*
75     * Sanity check
76     */
77    if (jcr->xattr_data->content_length <= 0) {
78       return bxattr_exit_ok;
79    }
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->content);
94    msgsave = sd->msg;
95    sd->msg = jcr->xattr_data->content;
96    sd->msglen = jcr->xattr_data->content_length;
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->content = check_pool_memory_size(jcr->xattr_data->content, expected_serialize_len + 10);
219    ser_begin(jcr->xattr_data->content, 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->content, expected_serialize_len + 10);
240    jcr->xattr_data->content_length = ser_length(jcr->xattr_data->content);
241    return jcr->xattr_data->content_length;
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->content, jcr->xattr_data->content_length);
467    while (unser_length(jcr->xattr_data->content) < jcr->xattr_data->content_length) {
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->content, jcr->xattr_data->content_length);
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->xattr_data->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->xattr_data->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    case S_IFDIR:
959       /*
960        * Get any acl on the xattr.
961        */
962       if (solaris_save_xattr_acl(jcr, attrfd, attrname, &acl_text) != bxattr_exit_ok)
963          goto bail_out;
964
965       /*
966        * See if this is the toplevel_hidden_dir being saved.
967        */
968       if (toplevel_hidden_dir) {
969          /*
970           * Save the data for later storage when we encounter a real xattr. We store the data
971           * in the jcr->xattr_data->content buffer and flush that just before sending out the
972           * first real xattr. Encode the stat struct into an ASCII representation and jump
973           * out of the function.
974           */
975          encode_stat(attribs, &st, 0, stream);
976          cnt = bsnprintf(buffer, sizeof(buffer),
977                          "%s%c%s%c%s%c",
978                          target_attrname, 0, attribs, 0, (acl_text) ? acl_text : "", 0);
979          pm_memcpy(jcr->xattr_data->content, buffer, cnt);
980          jcr->xattr_data->content_length = cnt;
981          goto bail_out;
982       } else {
983          /*
984           * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
985           * Encode the stat struct into an ASCII representation.
986           */
987          encode_stat(attribs, &st, 0, stream);
988          cnt = bsnprintf(buffer, sizeof(buffer),
989                          "%s%c%s%c%s%c",
990                          target_attrname, 0, attribs, 0, (acl_text) ? acl_text : "", 0);
991       }
992       break;
993    case S_IFREG:
994       /*
995        * If this is a hardlinked file check the inode cache for a hit.
996        */
997       if (st.st_nlink > 1) {
998          /*
999           * See if the cache already knows this inode number.
1000           */
1001          if ((xlce = find_xattr_link_cache_entry(jcr, st.st_ino)) != NULL) {
1002             /*
1003              * Generate a xattr encoding with the reference to the target in there.
1004              */
1005             encode_stat(attribs, &st, st.st_ino, stream);
1006             cnt = bsnprintf(buffer, sizeof(buffer),
1007                             "%s%c%s%c%s%c",
1008                             target_attrname, 0, attribs, 0, xlce->target, 0);
1009             pm_memcpy(jcr->xattr_data->content, buffer, cnt);
1010             jcr->xattr_data->content_length = cnt;
1011             retval = send_xattr_stream(jcr, stream);
1012
1013             /*
1014              * For a hard linked file we are ready now, no need to recursively save the attributes.
1015              */
1016             goto bail_out;
1017          }
1018
1019          /*
1020           * Store this hard linked file in the cache.
1021           * Store the name relative to the top level xattr space.
1022           */
1023          add_xattr_link_cache_entry(jcr, st.st_ino, target_attrname + 1);
1024       }
1025
1026       /*
1027        * Get any acl on the xattr.
1028        */
1029       if (solaris_save_xattr_acl(jcr, attrfd, attrname, &acl_text) != bxattr_exit_ok) {
1030          goto bail_out;
1031       }
1032
1033       /*
1034        * Encode the stat struct into an ASCII representation.
1035        */
1036       encode_stat(attribs, &st, 0, stream);
1037       cnt = bsnprintf(buffer, sizeof(buffer),
1038                      "%s%c%s%c%s%c",
1039                      target_attrname, 0, attribs, 0, (acl_text) ? acl_text : "", 0);
1040
1041       /*
1042        * Open the extended or extensible attribute file.
1043        */
1044       if ((attrfd = openat(fd, attrname, O_RDONLY)) < 0) {
1045          switch (errno) {
1046          case ENOENT:
1047             retval = bxattr_exit_ok;
1048             goto bail_out;
1049          default:
1050             Mmsg3(jcr->errmsg, _("Unable to open xattr %s on \"%s\": ERR=%s\n"),
1051                   target_attrname, jcr->last_fname, be.bstrerror());
1052             Dmsg3(100, "openat of xattr %s on \"%s\" failed: ERR=%s\n",
1053                   target_attrname, jcr->last_fname, be.bstrerror());
1054             goto bail_out;
1055          }
1056       }
1057       break;
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->content, buffer, cnt);
1085       jcr->xattr_data->content_length = cnt;
1086       retval = send_xattr_stream(jcr, stream);
1087
1088       if (retval == bxattr_exit_ok) {
1089          jcr->xattr_data->nr_saved++;
1090       }
1091
1092       /*
1093        * For a soft linked file we are ready now, no need to recursively save the attributes.
1094        */
1095       goto bail_out;
1096    default:
1097       goto bail_out;
1098    }
1099
1100    /*
1101     * See if this is the first real xattr being saved.
1102     * If it is save the toplevel_hidden_dir attributes first.
1103     * This is easy as its stored already in the jcr->xattr_data->content buffer.
1104     */
1105    if (jcr->xattr_data->nr_saved == 0) {
1106       retval = send_xattr_stream(jcr, STREAM_XATTR_SOLARIS);
1107       if (retval != bxattr_exit_ok) {
1108          goto bail_out;
1109       }
1110       jcr->xattr_data->nr_saved++;
1111    }
1112
1113    pm_memcpy(jcr->xattr_data->content, buffer, cnt);
1114    jcr->xattr_data->content_length = cnt;
1115
1116    /*
1117     * Only dump the content of regular files.
1118     */
1119    switch (st.st_mode & S_IFMT) {
1120    case S_IFREG:
1121       if (st.st_size > 0) {
1122          /*
1123           * Protect ourself against things getting out of hand.
1124           */
1125          if (st.st_size >= MAX_XATTR_STREAM) {
1126             Mmsg2(jcr->errmsg, _("Xattr stream on file \"%s\" exceeds maximum size of %d bytes\n"),
1127                   jcr->last_fname, MAX_XATTR_STREAM);
1128             goto bail_out;
1129          }
1130
1131          while ((cnt = read(attrfd, buffer, sizeof(buffer))) > 0) {
1132             jcr->xattr_data->content = check_pool_memory_size(jcr->xattr_data->content, jcr->xattr_data->content_length + cnt);
1133             memcpy(jcr->xattr_data->content + jcr->xattr_data->content_length, buffer, cnt);
1134             jcr->xattr_data->content_length += cnt;
1135          }
1136
1137          if (cnt < 0) {
1138             Mmsg2(jcr->errmsg, _("Unable to read content of xattr %s on file \"%s\"\n"),
1139                   target_attrname, jcr->last_fname);
1140             Dmsg2(100, "read of data from xattr %s on \"%s\" failed\n",
1141                   target_attrname, jcr->last_fname);
1142             goto bail_out;
1143          }
1144       }
1145       break;
1146
1147    default:
1148       break;
1149    }
1150
1151    if (retval) {
1152       retval = send_xattr_stream(jcr, stream);
1153       if (retval == bxattr_exit_ok) {
1154          jcr->xattr_data->nr_saved++;
1155       }
1156    }
1157
1158    /*
1159     * Recursivly call solaris_save_extended_attributes for archiving the attributes
1160     * available on this extended attribute.
1161     */
1162    if (retval) {
1163       retval = solaris_save_xattrs(jcr, xattr_namespace, attrname);
1164       
1165       /*
1166        * The recursive call could change our working dir so change back to the wanted workdir.
1167        */
1168       if (fchdir(fd) < 0) {
1169          switch (errno) {
1170          case ENOENT:
1171             retval = bxattr_exit_ok;
1172             goto bail_out;
1173          default:
1174             Mmsg2(jcr->errmsg, _("Unable to chdir to xattr space of file \"%s\": ERR=%s\n"),
1175                   jcr->last_fname, be.bstrerror());
1176             Dmsg3(100, "Unable to fchdir to xattr space of file \"%s\" using fd %d: ERR=%s\n",
1177                   jcr->last_fname, fd, be.bstrerror());
1178             goto bail_out;
1179          }
1180       }
1181    }
1182
1183 bail_out:
1184    if (acl_text) {
1185       free(acl_text);
1186    }
1187    if (attrfd != -1) {
1188       close(attrfd);
1189    }
1190    return retval;
1191 }
1192
1193 static bxattr_exit_code solaris_save_xattrs(JCR *jcr, const char *xattr_namespace, const char *attr_parent)
1194 {
1195    const char *name;
1196    int fd, filefd = -1, attrdirfd = -1;
1197    DIR *dirp;
1198    struct dirent *dp;
1199    char current_xattr_namespace[PATH_MAX];
1200    bxattr_exit_code retval = bxattr_exit_error;
1201    berrno be;
1202  
1203    /*
1204     * Determine what argument to use. Use attr_parent when set
1205     * (recursive call) or jcr->last_fname for first call. Also save
1206     * the current depth of the xattr_space we are in.
1207     */
1208    if (attr_parent) {
1209       name = attr_parent;
1210       if (xattr_namespace) {
1211          bsnprintf(current_xattr_namespace, sizeof(current_xattr_namespace), "%s%s/",
1212                    xattr_namespace, attr_parent);
1213       } else {
1214          bstrncpy(current_xattr_namespace, "/", sizeof(current_xattr_namespace));
1215       }
1216    } else {
1217       name = jcr->last_fname;
1218       bstrncpy(current_xattr_namespace, "/", sizeof(current_xattr_namespace));
1219    }
1220
1221    /*
1222     * Open the file on which to save the xattrs read-only.
1223     */
1224    if ((filefd = open(name, O_RDONLY | O_NONBLOCK)) < 0) {
1225       switch (errno) {
1226       case ENOENT:
1227          retval = bxattr_exit_ok;
1228          goto bail_out;
1229       default:
1230          Mmsg2(jcr->errmsg, _("Unable to open file \"%s\": ERR=%s\n"),
1231                jcr->last_fname, be.bstrerror());
1232          Dmsg2(100, "Unable to open file \"%s\": ERR=%s\n",
1233                jcr->last_fname, be.bstrerror());
1234          goto bail_out;
1235       }
1236    }
1237
1238    /*
1239     * Open the xattr naming space.
1240     */
1241    if ((attrdirfd = openat(filefd, ".", O_RDONLY | O_XATTR)) < 0) {
1242       switch (errno) {
1243       case EINVAL:
1244          /*
1245           * Gentile way of the system saying this type of xattr layering is not supported.
1246           * Which is not problem we just forget about this this xattr.
1247           * But as this is not an error we return a positive return value.
1248           */
1249          retval = bxattr_exit_ok;
1250          goto bail_out;
1251       case ENOENT:
1252          retval = bxattr_exit_ok;
1253          goto bail_out;
1254       default:
1255          Mmsg3(jcr->errmsg, _("Unable to open xattr space %s on file \"%s\": ERR=%s\n"),
1256                name, jcr->last_fname, be.bstrerror());
1257          Dmsg3(100, "Unable to open xattr space %s on file \"%s\": ERR=%s\n",
1258                name, jcr->last_fname, be.bstrerror());
1259          goto bail_out;
1260       }
1261    }
1262
1263   /*
1264    * We need to change into the attribute directory to determine if each of the
1265    * attributes should be saved.
1266    */
1267    if (fchdir(attrdirfd) < 0) {
1268       Mmsg2(jcr->errmsg, _("Unable to chdir to xattr space on file \"%s\": ERR=%s\n"),
1269             jcr->last_fname, be.bstrerror());
1270       Dmsg3(100, "Unable to fchdir to xattr space on file \"%s\" using fd %d: ERR=%s\n",
1271             jcr->last_fname, attrdirfd, be.bstrerror());
1272       goto bail_out;
1273    }
1274
1275    /*
1276     * Save the data of the toplevel xattr hidden_dir. We save this one before anything
1277     * else because the readdir returns "." entry after the extensible attr entry.
1278     * And as we want this entry before anything else we better just save its data.
1279     */
1280    if (!attr_parent)
1281       solaris_save_xattr(jcr, attrdirfd, current_xattr_namespace, ".",
1282                          true, STREAM_XATTR_SOLARIS);
1283
1284    if ((fd = dup(attrdirfd)) == -1 ||
1285        (dirp = fdopendir(fd)) == (DIR *)NULL) {
1286       Mmsg2(jcr->errmsg, _("Unable to list the xattr space on file \"%s\": ERR=%s\n"),
1287             jcr->last_fname, be.bstrerror());
1288       Dmsg3(100, "Unable to fdopendir xattr space on file \"%s\" using fd %d: ERR=%s\n",
1289             jcr->last_fname, fd, be.bstrerror());
1290
1291       goto bail_out;
1292    }
1293
1294    /*
1295     * Walk the namespace.
1296     */
1297    while (dp = readdir(dirp)) {
1298       /*
1299        * Skip only the toplevel . dir.
1300        */
1301       if (!attr_parent && !strcmp(dp->d_name, "."))
1302          continue;
1303
1304       /*
1305        * Skip all .. directories
1306        */
1307       if (!strcmp(dp->d_name, ".."))
1308          continue;
1309
1310       Dmsg3(400, "processing extended attribute %s%s on file \"%s\"\n",
1311          current_xattr_namespace, dp->d_name, jcr->last_fname);
1312
1313 #if defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED)
1314       /*
1315        * We are not interested in read-only extensible attributes.
1316        */
1317       if (!strcmp(dp->d_name, VIEW_READONLY)) {
1318          Dmsg3(400, "Skipping readonly extensible attributes %s%s on file \"%s\"\n",
1319             current_xattr_namespace, dp->d_name, jcr->last_fname);
1320
1321          continue;
1322       }
1323
1324       /*
1325        * We are only interested in read-write extensible attributes
1326        * when they contain non-transient values.
1327        */
1328       if (!strcmp(dp->d_name, VIEW_READWRITE)) {
1329          /*
1330           * Determine if there are non-transient system attributes at the toplevel.
1331           * We need to provide a fd to the open file.
1332           */
1333          if (!solaris_has_non_transient_extensible_attributes(filefd)) {
1334             Dmsg3(400, "Skipping transient extensible attributes %s%s on file \"%s\"\n",
1335                current_xattr_namespace, dp->d_name, jcr->last_fname);
1336             continue;
1337          }
1338
1339          /*
1340           * Save the xattr.
1341           */
1342          solaris_save_xattr(jcr, attrdirfd, current_xattr_namespace, dp->d_name,
1343                             false, STREAM_XATTR_SOLARIS_SYS);
1344          continue;
1345       }
1346 #endif /* HAVE_SYS_NVPAIR_H && _PC_SATTR_ENABLED */
1347
1348       /*
1349        * Save the xattr.
1350        */
1351       solaris_save_xattr(jcr, attrdirfd, current_xattr_namespace, dp->d_name,
1352                          false, STREAM_XATTR_SOLARIS);
1353    }
1354
1355    closedir(dirp);
1356    retval = bxattr_exit_ok;
1357
1358 bail_out:
1359    if (attrdirfd != -1)
1360       close(attrdirfd);
1361    if (filefd != -1)
1362       close(filefd);
1363    return retval;
1364 }
1365
1366 #ifdef HAVE_ACL
1367 static bxattr_exit_code solaris_restore_xattr_acl(JCR *jcr, int fd, const char *attrname, char *acl_text)
1368 {
1369 #ifdef HAVE_EXTENDED_ACL
1370    int error;
1371    acl_t *aclp = NULL;
1372    berrno be;
1373
1374    if ((error = acl_fromtext(acl_text, &aclp)) != 0) {
1375       Mmsg1(jcr->errmsg, _("Unable to convert acl from text on file \"%s\"\n"),
1376             jcr->last_fname);
1377       return bxattr_exit_error;
1378    }
1379
1380    if ((fd != -1 && facl_set(fd, aclp) != 0) ||
1381         acl_set(attrname, aclp) != 0) {
1382       Mmsg3(jcr->errmsg, _("Unable to restore acl of xattr %s on file \"%s\": ERR=%s\n"),
1383             attrname, jcr->last_fname, be.bstrerror());
1384       Dmsg3(100, "Unable to restore acl of xattr %s on file \"%s\": ERR=%s\n",
1385             attrname, jcr->last_fname, be.bstrerror());
1386       return bxattr_exit_error;
1387    }
1388
1389    if (aclp) {
1390       acl_free(aclp);
1391    }
1392    return bxattr_exit_ok;
1393
1394 #else /* HAVE_EXTENDED_ACL */
1395    int n;
1396    aclent_t *acls = NULL;
1397    berrno be;
1398
1399    acls = aclfromtext(acl_text, &n);
1400    if (!acls) {
1401       if ((fd != -1 && facl(fd, SETACL, n, acls) != 0) ||
1402            acl(attrname, SETACL, n, acls) != 0) {
1403          Mmsg3(jcr->errmsg, _("Unable to restore acl of xattr %s on file \"%s\": ERR=%s\n"),
1404                attrname, jcr->last_fname, be.bstrerror());
1405          Dmsg3(100, "Unable to restore acl of xattr %s on file \"%s\": ERR=%s\n",
1406                attrname, jcr->last_fname, be.bstrerror());
1407          return bxattr_exit_error;
1408       }
1409    }
1410
1411    if (acls) {
1412       free(acls);
1413    }
1414    return bxattr_exit_ok;
1415
1416 #endif /* HAVE_EXTENDED_ACL */
1417
1418 }
1419 #endif /* HAVE_ACL */
1420
1421 static bxattr_exit_code solaris_restore_xattrs(JCR *jcr, bool is_extensible)
1422 {
1423    int fd, filefd = -1, attrdirfd = -1, attrfd = -1;
1424    int used_bytes, total_bytes, cnt;
1425    char *bp, *target_attrname, *attribs;
1426    char *linked_target = NULL;
1427    char *acl_text = NULL;
1428    char *data = NULL;
1429    int32_t inum;
1430    struct stat st;
1431    struct timeval times[2];
1432    bxattr_exit_code retval = bxattr_exit_error;
1433    berrno be;
1434
1435    /*
1436     * Parse the xattr stream. First the part that is the same for all xattrs.
1437     */
1438    used_bytes = 0;
1439    total_bytes = jcr->xattr_data->content_length;
1440
1441    /*
1442     * The name of the target xattr has a leading / we are not interested
1443     * in that so skip it when decoding the string. We always start a the /
1444     * of the xattr space anyway.
1445     */
1446    target_attrname = jcr->xattr_data->content + 1;
1447    if ((bp = strchr(target_attrname, '\0')) == (char *)NULL ||
1448        (used_bytes = (bp - jcr->xattr_data->content)) >= (total_bytes - 1)) {
1449       goto parse_error;
1450    }
1451    attribs = ++bp;
1452
1453    /*
1454     * Open the file on which to restore the xattrs read-only.
1455     */
1456    if ((filefd = open(jcr->last_fname, O_RDONLY | O_NONBLOCK)) < 0) {
1457       Mmsg2(jcr->errmsg, _("Unable to open file \"%s\": ERR=%s\n"),
1458             jcr->last_fname, be.bstrerror());
1459       Dmsg2(100, "Unable to open file \"%s\": ERR=%s\n",
1460             jcr->last_fname, be.bstrerror());
1461       goto bail_out;
1462    }
1463
1464    /*
1465     * Open the xattr naming space and make it the current working dir.
1466     */
1467    if ((attrdirfd = openat(filefd, ".", O_RDONLY | O_XATTR)) < 0) {
1468       Mmsg2(jcr->errmsg, _("Unable to open xattr space on file \"%s\": ERR=%s\n"),
1469             jcr->last_fname, be.bstrerror());
1470       Dmsg2(100, "Unable to open xattr space on file \"%s\": ERR=%s\n",
1471             jcr->last_fname, be.bstrerror());
1472       goto bail_out;
1473    }
1474
1475    if (fchdir(attrdirfd) < 0) {
1476       Mmsg2(jcr->errmsg, _("Unable to chdir to xattr space on file \"%s\": ERR=%s\n"),
1477             jcr->last_fname, be.bstrerror());
1478       Dmsg3(100, "Unable to fchdir to xattr space on file \"%s\" using fd %d: ERR=%s\n",
1479             jcr->last_fname, attrdirfd, be.bstrerror());
1480       goto bail_out;
1481    }
1482
1483    /*
1484     * Try to open the correct xattr subdir based on the target_attrname given.
1485     * e.g. check if its a subdir attrname. Each / in the string makes us go
1486     * one level deeper.
1487     */
1488    while ((bp = strchr(target_attrname, '/')) != (char *)NULL) {
1489       *bp = '\0';
1490
1491       if ((fd = open(target_attrname, O_RDONLY | O_NONBLOCK)) < 0) {
1492          Mmsg3(jcr->errmsg, _("Unable to open xattr %s on file \"%s\": ERR=%s\n"),
1493                target_attrname, jcr->last_fname, be.bstrerror());
1494          Dmsg3(100, "Unable to open xattr %s on file \"%s\": ERR=%s\n",
1495                target_attrname, jcr->last_fname, be.bstrerror());
1496          goto bail_out;
1497       }
1498
1499       close(filefd);
1500       filefd = fd;
1501
1502       /*
1503        * Open the xattr naming space.
1504        */
1505       if ((fd = openat(filefd, ".", O_RDONLY | O_XATTR)) < 0) {
1506          Mmsg3(jcr->errmsg, _("Unable to open xattr space %s on file \"%s\": ERR=%s\n"),
1507                target_attrname, jcr->last_fname, be.bstrerror());
1508          Dmsg3(100, "Unable to open xattr space %s on file \"%s\": ERR=%s\n",
1509                target_attrname, jcr->last_fname, be.bstrerror());
1510          goto bail_out;
1511       }
1512
1513       close(attrdirfd);
1514       attrdirfd = fd;
1515
1516       /*
1517        * Make the xattr space our current workingdir.
1518        */
1519       if (fchdir(attrdirfd) < 0) {
1520          Mmsg3(jcr->errmsg, _("Unable to chdir to xattr space %s on file \"%s\": ERR=%s\n"),
1521                target_attrname, jcr->last_fname, be.bstrerror());
1522          Dmsg4(100, "Unable to fchdir to xattr space %s on file \"%s\" using fd %d: ERR=%s\n",
1523                target_attrname, jcr->last_fname, attrdirfd, be.bstrerror());
1524          goto bail_out;
1525       }
1526
1527       target_attrname = ++bp;
1528    }
1529
1530    /*
1531     * Decode the attributes from the stream.
1532     */
1533    decode_stat(attribs, &st, &inum);
1534
1535    /*
1536     * Decode the next field (acl_text).
1537     */
1538    if ((bp = strchr(attribs, '\0')) == (char *)NULL ||
1539        (used_bytes = (bp - jcr->xattr_data->content)) >= (total_bytes - 1)) {
1540       goto parse_error;
1541    }
1542    acl_text = ++bp;
1543
1544    /*
1545     * Based on the filetype perform the correct action. We support most filetypes here, more
1546     * then the actual implementation on Solaris supports so some code may never get executed
1547     * due to limitations in the implementation.
1548     */
1549    switch (st.st_mode & S_IFMT) {
1550    case S_IFIFO:
1551       /*
1552        * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
1553        */
1554       unlinkat(attrdirfd, target_attrname, 0);
1555       if (mkfifo(target_attrname, st.st_mode) < 0) {
1556          Mmsg3(jcr->errmsg, _("Unable to mkfifo xattr %s on file \"%s\": ERR=%s\n"),
1557                target_attrname, jcr->last_fname, be.bstrerror());
1558          Dmsg3(100, "Unable to mkfifo xattr %s on file \"%s\": ERR=%s\n",
1559                target_attrname,  jcr->last_fname, be.bstrerror());
1560          goto bail_out;
1561       }
1562       break;
1563    case S_IFCHR:
1564    case S_IFBLK:
1565       /*
1566        * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
1567        */
1568       unlinkat(attrdirfd, target_attrname, 0);
1569       if (mknod(target_attrname, st.st_mode, st.st_rdev) < 0) {
1570          Mmsg3(jcr->errmsg, _("Unable to mknod xattr %s on file \"%s\": ERR=%s\n"),
1571                target_attrname, jcr->last_fname, be.bstrerror());
1572          Dmsg3(100, "Unable to mknod xattr %s on file \"%s\": ERR=%s\n",
1573                target_attrname,  jcr->last_fname, be.bstrerror());
1574          goto bail_out;
1575       }
1576       break;
1577    case S_IFDIR:
1578       /*
1579        * If its not the hidden_dir create the entry.
1580        * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
1581        */
1582       if (strcmp(target_attrname, ".")) {
1583          unlinkat(attrdirfd, target_attrname, AT_REMOVEDIR);
1584          if (mkdir(target_attrname, st.st_mode) < 0) {
1585             Jmsg3(jcr, M_WARNING, 0, _("Unable to mkdir xattr %s on file \"%s\": ERR=%s\n"),
1586                target_attrname, jcr->last_fname, be.bstrerror());
1587             Dmsg3(100, "Unable to mkdir xattr %s on file \"%s\": ERR=%s\n",
1588                target_attrname,  jcr->last_fname, be.bstrerror());
1589             goto bail_out;
1590          }
1591       }
1592       break;
1593    case S_IFREG:
1594       /*
1595        * See if this is a hard linked file. e.g. inum != 0
1596        */
1597       if (inum != 0) {
1598          linked_target = bp;
1599
1600          unlinkat(attrdirfd, target_attrname, 0);
1601          if (link(linked_target, target_attrname) < 0) {
1602             Mmsg4(jcr->errmsg, _("Unable to link xattr %s to %s on file \"%s\": ERR=%s\n"),
1603                   target_attrname, linked_target, jcr->last_fname, be.bstrerror());
1604             Dmsg4(100, "Unable to link xattr %s to %s on file \"%s\": ERR=%s\n",
1605                   target_attrname, linked_target, jcr->last_fname, be.bstrerror());
1606             goto bail_out;
1607          }
1608
1609          /*
1610           * Successfully restored xattr.
1611           */
1612          retval = bxattr_exit_ok;
1613          goto bail_out;
1614       } else {
1615          if ((bp = strchr(acl_text, '\0')) == (char *)NULL ||
1616              (used_bytes = (bp - jcr->xattr_data->content)) >= total_bytes) {
1617             goto parse_error;
1618          }
1619
1620          if (used_bytes < (total_bytes - 1))
1621             data = ++bp;
1622
1623          /*
1624           * Restore the actual xattr.
1625           */
1626          if (!is_extensible) {
1627             unlinkat(attrdirfd, target_attrname, 0);
1628          }
1629
1630          if ((attrfd = openat(attrdirfd, target_attrname, O_RDWR | O_CREAT | O_TRUNC, st.st_mode)) < 0) {
1631             Mmsg3(jcr->errmsg, _("Unable to open xattr %s on file \"%s\": ERR=%s\n"),
1632                   target_attrname, jcr->last_fname, be.bstrerror());
1633             Dmsg3(100, "Unable to open xattr %s on file \"%s\": ERR=%s\n",
1634                   target_attrname, jcr->last_fname, be.bstrerror());
1635             goto bail_out;
1636          }
1637       }
1638
1639       /*
1640        * Restore the actual data.
1641        */
1642       if (st.st_size > 0) {
1643          used_bytes = (data - jcr->xattr_data->content);
1644          cnt = total_bytes - used_bytes;
1645
1646          /*
1647           * Do a sanity check, the st.st_size should be the same as the number of bytes
1648           * we have available as data of the stream.
1649           */
1650          if (cnt != st.st_size) {
1651             Mmsg2(jcr->errmsg, _("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             Dmsg2(100, "Unable to restore data of xattr %s on file \"%s\": Not all data available in xattr stream\n",
1654                   target_attrname, jcr->last_fname);
1655             goto bail_out;
1656          }
1657
1658          while (cnt > 0) {
1659             cnt = write(attrfd, data, cnt);
1660             if (cnt < 0) {
1661                Mmsg3(jcr->errmsg, _("Unable to restore data of xattr %s on file \"%s\": ERR=%s\n"),
1662                      target_attrname, jcr->last_fname, be.bstrerror());
1663                Dmsg3(100, "Unable to restore data of xattr %s on file \"%s\": ERR=%s\n",
1664                      target_attrname, jcr->last_fname, be.bstrerror());
1665                goto bail_out;
1666             }
1667
1668             used_bytes += cnt;
1669             data += cnt;
1670             cnt = total_bytes - used_bytes;
1671          }
1672       }
1673       break;
1674    case S_IFLNK:
1675       /*
1676        * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
1677        */
1678       linked_target = bp;
1679
1680       if (symlink(linked_target, target_attrname) < 0) {
1681          Mmsg4(jcr->errmsg, _("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 bail_out;
1686       }
1687
1688       /*
1689        * Successfully restored xattr.
1690        */
1691       retval = bxattr_exit_ok;
1692       goto bail_out;
1693    default:
1694       goto bail_out;
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 = bxattr_exit_ok;
1709             break;
1710          case ENOENT:
1711             retval = bxattr_exit_ok;
1712             break;
1713          default:
1714             Mmsg3(jcr->errmsg, _("Unable to restore owner of xattr %s on file \"%s\": ERR=%s\n"),
1715                   target_attrname, jcr->last_fname, be.bstrerror());
1716             Dmsg3(100, "Unable to restore owner of xattr %s on file \"%s\": ERR=%s\n",
1717                   target_attrname, jcr->last_fname, be.bstrerror());
1718          }
1719          goto bail_out;
1720       }
1721    }
1722
1723 #ifdef HAVE_ACL
1724    if (acl_text && *acl_text)
1725       if (solaris_restore_xattr_acl(jcr, attrfd, target_attrname, acl_text) != bxattr_exit_ok)
1726          goto bail_out;
1727 #endif /* HAVE_ACL */
1728
1729    /*
1730     * For a non extensible attribute restore access and modification time on the xattr.
1731     */
1732    if (!is_extensible) {
1733       times[0].tv_sec = st.st_atime;
1734       times[0].tv_usec = 0;
1735       times[1].tv_sec = st.st_mtime;
1736       times[1].tv_usec = 0;
1737
1738       if (futimesat(attrdirfd, target_attrname, times) < 0) {
1739          Mmsg3(jcr->errmsg, _("Unable to restore filetimes of xattr %s on file \"%s\": ERR=%s\n"),
1740                target_attrname, jcr->last_fname, be.bstrerror());
1741          Dmsg3(100, "Unable to restore filetimes of xattr %s on file \"%s\": ERR=%s\n",
1742                target_attrname, jcr->last_fname, be.bstrerror());
1743          goto bail_out;
1744       }
1745    }
1746
1747    /*
1748     * Successfully restored xattr.
1749     */
1750    retval = bxattr_exit_ok;
1751    goto bail_out;
1752
1753 parse_error:
1754    Mmsg1(jcr->errmsg, _("Illegal xattr stream, failed to parse xattr stream on file \"%s\"\n"),
1755          jcr->last_fname);
1756    Dmsg1(100, "Illegal xattr stream, failed to parse xattr stream on file \"%s\"\n",
1757          jcr->last_fname);
1758
1759 bail_out:
1760    if (attrfd != -1) {
1761       close(attrfd);
1762    }
1763    if (attrdirfd != -1) {
1764       close(attrdirfd);
1765    }
1766    if (filefd != -1) {
1767       close(filefd);
1768    }
1769    return retval;
1770 }
1771
1772 static bxattr_exit_code solaris_build_xattr_streams(JCR *jcr, FF_PKT *ff_pkt)
1773 {
1774    char cwd[PATH_MAX];
1775    bxattr_exit_code retval = bxattr_exit_ok;
1776
1777    /*
1778     * First see if extended attributes or extensible attributes are present.
1779     * If not just pretend things went ok.
1780     */
1781    if (pathconf(jcr->last_fname, _PC_XATTR_EXISTS) > 0) {
1782       jcr->xattr_data->nr_saved = 0;
1783       jcr->xattr_data->link_cache = New(alist(10, not_owned_by_alist));
1784
1785       /*
1786        * As we change the cwd in the save function save the current cwd
1787        * for restore after return from the solaris_save_xattrs function.
1788        */
1789       getcwd(cwd, sizeof(cwd));
1790       retval = solaris_save_xattrs(jcr, NULL, NULL);
1791       chdir(cwd);
1792       delete jcr->xattr_data->link_cache;
1793       jcr->xattr_data->link_cache = NULL;
1794    }
1795    return retval;
1796 }
1797
1798 static bxattr_exit_code solaris_parse_xattr_streams(JCR *jcr, int stream)
1799 {
1800    char cwd[PATH_MAX];
1801    bool is_extensible = false;
1802    bxattr_exit_code retval;
1803
1804    /*
1805     * First make sure we can restore xattr on the filesystem.
1806     */
1807    switch (stream) {
1808 #if defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED)
1809    case STREAM_XATTR_SOLARIS_SYS:
1810       if (pathconf(jcr->last_fname, _PC_SATTR_ENABLED) <= 0) {
1811          Qmsg1(jcr, M_WARNING, 0,
1812                _("Failed to restore extensible attributes on file \"%s\"\n"),
1813                jcr->last_fname);
1814          Dmsg1(100, "Unable to restore extensible attributes on file \"%s\", filesystem doesn't support this\n",
1815             jcr->last_fname);
1816          return bxattr_exit_error;
1817       }
1818
1819       is_extensible = true;
1820       break;
1821 #endif
1822    case STREAM_XATTR_SOLARIS:
1823       if (pathconf(jcr->last_fname, _PC_XATTR_ENABLED) <= 0) {
1824          Qmsg1(jcr, M_WARNING, 0,
1825                _("Failed to restore extended attributes on file \"%s\"\n"),
1826                jcr->last_fname);
1827          Dmsg1(100, "Unable to restore extended attributes on file \"%s\", filesystem doesn't support this\n",
1828             jcr->last_fname);
1829          return bxattr_exit_error;
1830       }
1831       break;
1832    default:
1833       return bxattr_exit_error;
1834    }
1835
1836    /*
1837     * As we change the cwd in the restore function save the current cwd
1838     * for restore after return from the solaris_restore_xattrs function.
1839     */
1840    getcwd(cwd, sizeof(cwd));
1841    retval = solaris_restore_xattrs(jcr, is_extensible);
1842    chdir(cwd);
1843    return retval;
1844 }
1845
1846
1847 /*
1848  * Function pointers to the build and parse function to use for these xattrs.
1849  */
1850 static bxattr_exit_code (*os_build_xattr_streams)(JCR *jcr, FF_PKT *ff_pkt) = solaris_build_xattr_streams;
1851 static bxattr_exit_code (*os_parse_xattr_streams)(JCR *jcr, int stream) = solaris_parse_xattr_streams;
1852
1853 #endif /* defined(HAVE_SUN_OS) */
1854
1855 /*
1856  * Entry points when compiled with support for XATTRs on a supported platform.
1857  */
1858 bxattr_exit_code build_xattr_streams(JCR *jcr, FF_PKT *ff_pkt)
1859 {
1860    if (os_build_xattr_streams) {
1861       return (*os_build_xattr_streams)(jcr, ff_pkt);
1862    }
1863    return bxattr_exit_error;
1864 }
1865
1866 bxattr_exit_code parse_xattr_streams(JCR *jcr, int stream)
1867 {
1868    unsigned int cnt;
1869
1870    if (os_parse_xattr_streams) {
1871       /*
1872        * See if we can parse this stream, and ifso give it a try.
1873        */
1874       for (cnt = 0; cnt < sizeof(os_default_xattr_streams) / sizeof(int); cnt++) {
1875          if (os_default_xattr_streams[cnt] == stream) {
1876             return (*os_parse_xattr_streams)(jcr, stream);
1877          }
1878       }
1879    }
1880    /*
1881     * Issue a warning and discard the message. But pretend the restore was ok.
1882     */
1883    Jmsg2(jcr, M_WARNING, 0,
1884       _("Can't restore Extended Attributes of %s - incompatible xattr stream encountered - %d\n"),
1885       jcr->last_fname, stream);
1886    return bxattr_exit_error;
1887 }
1888 #endif