]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/filed/xattr.c
67623481fa5afb36e8713b1b8839f4f512e557e6
[bacula/bacula] / bacula / src / filed / xattr.c
1 /*
2    Bacula(R) - The Network Backup Solution
3
4    Copyright (C) 2000-2015 Kern Sibbald
5    Copyright (C) 2008-2014 Free Software Foundation Europe e.V.
6
7    The original author of Bacula is Kern Sibbald, with contributions
8    from many others, a complete list can be found in the file AUTHORS.
9
10    You may use this file and others of this release according to the
11    license defined in the LICENSE file, which includes the Affero General
12    Public License, v3.0 ("AGPLv3") and some additional permissions and
13    terms pursuant to its AGPLv3 Section 7.
14
15    This notice must be preserved when any source code is 
16    conveyed and/or propagated.
17
18    Bacula(R) is a registered trademark of Kern Sibbald.
19 */
20 /* 
21  * Functions to handle Extended Attributes for bacula. 
22  * 
23  * Extended Attributes are so OS specific we only restore Extended Attributes if 
24  * they were saved using a filed on the same platform. 
25  * 
26  * Currently we support the following OSes: 
27  *   - AIX (Extended Attributes) 
28  *   - Darwin (Extended Attributes) 
29  *   - FreeBSD (Extended Attributes) 
30  *   - GNU HURD (Extended Attributes) 
31  *   - IRIX (Extended Attributes) 
32  *   - Linux (Extended Attributes) 
33  *   - NetBSD (Extended Attributes) 
34  *   - OpenBSD (Extended Attributes) 
35  *     (As it seems either they never implemented xattr or they are removed 
36  *      the support as it stated it was in version 3.1 but the current syscall 
37  *      tabled shows the extattr_ functions are not implemented. So as such we 
38  *      might eventually support xattr on OpenBSD when they implemented them using 
39  *      the same interface as FreeBSD and NetBSD. 
40  *   - Solaris (Extended Attributes and Extensible Attributes) 
41  *   - Tru64 (Extended Attributes) 
42  *
43  *   Written by Marco van Wieringen, November 2008 
44  *   Major overhaul January 2012 + June 2012 
45  *   Simplfied by Kern Sibbald, June 2015
46  */ 
47  
48 #include "bacula.h" 
49 #include "filed.h"   
50  
51 #ifndef HAVE_XATTR 
52 /* 
53  * Entry points when compiled without support for XATTRs or on an unsupported platform. 
54  */ 
55 bool backup_xattr_streams(JCR *jcr, FF_PKT *ff_pkt)
56 {
57    Jmsg(jcr, M_FATAL, 0, "XATTR backup requested but not configured in Bacula.\n");
58    return false;
59 }
60
61 bxattr_rtn_code restore_xattr_streams(JCR *jcr, int stream, char *content,
62                                     uint32_t content_length)
63 {
64    return bxattr_rtn_fatal;
65 }
66 #else 
67 /* 
68  * Send a XATTR stream to the SD.
69  */ 
70 static bxattr_rtn_code send_xattr_stream(JCR *jcr, int stream)
71
72    BSOCK *sd = jcr->store_bsock;
73    POOLMEM *msgsave;
74
75 #ifdef FD_NO_SEND_TEST 
76    return bxattr_rtn_ok;
77 #endif 
78
79    /* 
80     * Sanity check 
81     */ 
82    if (jcr->xattr_ctx->content_length <= 0) {
83       return bxattr_rtn_ok;
84    }
85  
86    /* 
87     * Send header 
88     */ 
89    if (!sd->fsend("%ld %d 0", jcr->JobFiles, stream)) {
90       Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
91             sd->bstrerror());
92       return bxattr_rtn_fatal;
93    } 
94  
95    /* 
96     * Send the buffer to the storage deamon 
97     */ 
98    Dmsg1(400, "Backing up XATTR <%s>\n", jcr->xattr_ctx->content);
99    msgsave = sd->msg;
100    sd->msg = jcr->xattr_ctx->content;
101    sd->msglen = jcr->xattr_ctx->content_length;
102    if (!sd->send()) {
103       sd->msg = msgsave;
104       sd->msglen = 0;
105       Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
106             sd->bstrerror());
107       return bxattr_rtn_fatal;
108    } 
109  
110    jcr->JobBytes += sd->msglen;
111    sd->msg = msgsave;
112    if (!sd->signal(BNET_EOD)) {
113       Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
114             sd->bstrerror());
115       return bxattr_rtn_fatal;
116    } 
117    Dmsg1(200, "XATTR of file: %s successfully backed up!\n", jcr->last_fname);
118    return bxattr_rtn_ok;
119
120  
121 /* 
122  * First some generic functions for OSes that use the same xattr encoding scheme. 
123  * Currently for all OSes except for Solaris. 
124  */ 
125 #ifndef HAVE_SUN_OS
126 static void xattr_drop_internal_table(alist *xattr_value_list)
127 {
128    xattr_t *current_xattr;
129    
130    if (!xattr_value_list) {
131       return;
132    }
133    /* Walk the list of xattrs and free allocated memory. */
134    foreach_alist(current_xattr, xattr_value_list) {
135       if (current_xattr->magic != XATTR_MAGIC) {
136          continue;
137       }
138       if (current_xattr->name) {
139          free(current_xattr->name);
140       }
141       if (current_xattr->value && current_xattr->value_length > 0) {
142          free(current_xattr->value);
143       }
144       free(current_xattr);
145    }
146    delete xattr_value_list;
147 }
148
149 /*
150  * The xattr stream for OSX, FreeBSD, Linux and NetBSD is a serialized stream of bytes 
151  * which encodes one or more xattr_t structures. 
152  * 
153  * The Serialized stream consists of the following elements: 
154  *    magic - A magic string which makes it easy to detect any binary incompatabilites 
155  *    name_length - The length of the following xattr name 
156  *    name - The name of the extended attribute 
157  *    value_length - The length of the following xattr data 
158  *    value - The actual content of the extended attribute 
159  * 
160  * This is repeated 1 or more times. 
161  * 
162  */ 
163 static uint32_t serialize_xattr_stream(JCR *jcr, uint32_t expected_serialize_len,
164                                        alist *xattr_value_list)
165
166    xattr_t *current_xattr;
167    ser_declare;
168  
169    /* 
170     * Make sure the serialized stream fits in the poolmem buffer. 
171     * We allocate some more to be sure the stream is gonna fit. 
172     */ 
173    jcr->xattr_ctx->content =
174    check_pool_memory_size(jcr->xattr_ctx->content, expected_serialize_len + 10);
175    ser_begin(jcr->xattr_ctx->content, expected_serialize_len + 10);
176  
177    /* 
178     * Walk the list of xattrs and serialize the data. 
179     */ 
180    foreach_alist(current_xattr, xattr_value_list) {
181       if (current_xattr->magic != XATTR_MAGIC) {
182          continue;                 /* Don't write invalid xattr */
183       }
184
185       ser_uint32(current_xattr->magic);
186       ser_uint32(current_xattr->name_length);
187       ser_bytes(current_xattr->name, current_xattr->name_length);
188
189       ser_uint32(current_xattr->value_length);
190       if (current_xattr->value_length > 0 && current_xattr->value) {
191          ser_bytes(current_xattr->value, current_xattr->value_length);
192          Dmsg3(100, "Backup xattr named %s, value %*s\n",
193                current_xattr->name, current_xattr->value, current_xattr->value);
194       } else {
195          Dmsg1(100, "Backup empty xattr named %s\n", current_xattr->name);
196       }
197    }
198
199    ser_end(jcr->xattr_ctx->content, expected_serialize_len + 10);
200    jcr->xattr_ctx->content_length = ser_length(jcr->xattr_ctx->content);
201    return jcr->xattr_ctx->content_length;
202 }
203
204 static bxattr_rtn_code unserialize_xattr_stream(JCR *jcr,
205                                                  char *content,
206                                                  uint32_t content_length,
207                                                  alist *xattr_value_list)
208 {
209    unser_declare;
210    xattr_t *current_xattr;
211
212    /*
213     * Restore the stream and call restore_xattr_on_file for each extended attribute.
214     *
215     * Start unserializing the data. We keep on looping while we have not
216     * unserialized all bytes in the stream.
217     */
218    unser_begin(content, content_length);
219    while (unser_length(content) < content_length) {
220       /* 
221        * First make sure the magic is present. This way we can easily catch corruption. 
222        * Any missing MAGIC is fatal we do NOT try to continue. 
223        */ 
224       current_xattr = (xattr_t *)malloc(sizeof(xattr_t));
225       unser_uint32(current_xattr->magic);
226       if (current_xattr->magic != XATTR_MAGIC) {
227          Mmsg1(jcr->errmsg, _("Invalid xattr stream, no XATTR_MAGIC on file \"%s\"\n"),
228                jcr->last_fname);
229          Dmsg1(100, "%s", jcr->errmsg);
230          free(current_xattr);
231          return bxattr_rtn_error;
232       }
233  
234       /* 
235        * Decode the valuepair. First decode the length of the name. 
236        */ 
237       unser_uint32(current_xattr->name_length);
238       if (current_xattr->name_length == 0) {
239          Mmsg1(jcr->errmsg, _("Invalid xattr stream, xattr name length <= 0 on file \"%s\"\n"),
240                jcr->last_fname);
241          Dmsg1(100, "%s", jcr->errmsg);
242          free(current_xattr);
243          return bxattr_rtn_error;
244       }
245  
246       /* 
247        * Allocate room for the name and decode its content. 
248        */ 
249       current_xattr->name = (char *)malloc(current_xattr->name_length + 1);
250       unser_bytes(current_xattr->name, current_xattr->name_length);
251  
252       /* 
253        * The xattr_name needs to be null terminated. 
254        */ 
255       current_xattr->name[current_xattr->name_length] = '\0';
256  
257       /* 
258        * Decode the value length. 
259        */ 
260       unser_uint32(current_xattr->value_length);
261  
262       if (current_xattr->value_length > 0) {
263          /* 
264           * Allocate room for the value and decode its content. 
265           */ 
266          current_xattr->value = (char *)malloc(current_xattr->value_length);
267          unser_bytes(current_xattr->value, current_xattr->value_length);
268  
269          Dmsg3(100, "Restoring xattr named %s, value %*s\n",
270                current_xattr->name, current_xattr->value, current_xattr->value);
271       } else {
272          current_xattr->value = NULL;
273          Dmsg1(100, "Restoring empty xattr named %s\n", current_xattr->name);
274       }
275
276       xattr_value_list->append(current_xattr);
277    }
278
279    unser_end(content, content_length);
280    return bxattr_rtn_ok;
281 }
282 #endif
283
284 /* 
285  * This is a supported OS, See what kind of interface we should use.
286  */ 
287 #if defined(HAVE_AIX_OS)
288  
289 #if (!defined(HAVE_LISTEA) && !defined(HAVE_LLISTEA)) || \
290     (!defined(HAVE_GETEA) && !defined(HAVE_LGETEA)) || \
291     (!defined(HAVE_SETEA) && !defined(HAVE_LSETEA))
292 #error "Missing full support for the Extended Attributes (EA) functions."
293 #endif
294
295 #ifdef HAVE_SYS_EA_H
296 #include <sys/ea.h>
297 #else
298 #error "Missing sys/ea.h header file"
299 #endif
300
301 /*
302  * Define the supported XATTR streams for this OS
303  */
304 static int os_default_xattr_streams[1] = {
305    STREAM_XATTR_AIX
306 };
307
308 /*
309  * Fallback to the non l-functions when those are not available.
310  */
311 #if defined(HAVE_GETEA) && !defined(HAVE_LGETEA)
312 #define lgetea getea
313 #endif
314 #if defined(HAVE_SETEA) && !defined(HAVE_LSETEA)
315 #define lsetea setea
316 #endif
317 #if defined(HAVE_LISTEA) && !defined(HAVE_LLISTEA)
318 #define llistea listea
319 #endif
320
321 static bxattr_rtn_code aix_xattr_build_streams(JCR *jcr, FF_PKT *ff_pkt)
322 {
323    char *bp;
324    bool skip_xattr;
325    char *xattr_list = NULL;
326    int cnt, xattr_count = 0;
327    uint32_t name_length;
328    int32_t xattr_list_len, xattr_value_len;
329    uint32_t expected_serialize_len = 0;
330    xattr_t *current_xattr;
331    alist *xattr_value_list = NULL;
332    bxattr_rtn_code retval = bxattr_rtn_error;
333
334    /*
335     * First get the length of the available list with extended attributes.
336     */
337    xattr_list_len = llistea(jcr->last_fname, NULL, 0);
338    if (xattr_list_len < 0) {
339       berrno be;
340       if (errno == ENOENT || errno == EFORMAT) {
341          retval = bxattr_rtn_ok;
342       } else if (errno == ENOTSUP) {
343          /*
344           * If the filesystem reports it doesn't support XATTRs we clear the
345           * BXATTR_FLAG_SAVE_NATIVE flag so we skip XATTR saves on all other files
346           * on the same filesystem. The BXATTR_FLAG_SAVE_NATIVE flags gets sets again
347           * when we change from one filesystem to an other.
348           */
349          jcr->xattr_ctx->flags &= ~BXATTR_FLAG_SAVE_NATIVE;
350          retval = bxattr_rtn_ok;
351       } else {
352          Mmsg2(jcr->errmsg, _("XATTR llistea error on file \"%s\": ERR=%s\n"),
353                jcr->last_fname, be.bstrerror());
354          Dmsg1(100, "%s", jcr->errmsg);
355       }
356       goto get_out;
357    } else if (xattr_list_len == 0) {
358       retval = bxattr_rtn_ok;
359       goto get_out;
360    }
361
362    /*
363     * Allocate room for the extented attribute list.
364     */
365    xattr_list = (char *)malloc(xattr_list_len + 1);
366    memset(xattr_list, 0, xattr_list_len + 1);
367
368    /*
369     * Get the actual list of extended attributes names for a file.
370     */
371    xattr_list_len = llistea(jcr->last_fname, xattr_list, xattr_list_len);
372    if (xattr_list_len < 0) {
373       berrno be;
374       if (errno == ENOENT || errno == EFORMAT) {
375          retval = bxattr_rtn_ok;
376       } else {
377          Mmsg2(jcr->errmsg, _("XATTR llistea error on file \"%s\": ERR=%s\n"),
378                jcr->last_fname, be.bstrerror());
379          Dmsg1(100, "%s", jcr->errmsg);
380       }
381       goto get_out;
382    }
383    xattr_list[xattr_list_len] = '\0';
384
385    /*
386     * Walk the list of extended attributes names and retrieve the data.
387     * We already count the bytes needed for serializing the stream later on.
388     */
389    for (bp = xattr_list; (bp - xattr_list) + 1 < xattr_list_len;
390         bp = strchr(bp, '\0') + 1) {
391       skip_xattr = false;
392
393       /*
394        * We want to skip certain xattrs which start with a 0xF8 character on AIX.
395        */
396       if (*bp == 0xF8) {
397          skip_xattr = true;
398       }
399
400       name_length = strlen(bp);
401       if (skip_xattr || name_length == 0) {
402          Dmsg1(100, "Skipping xattr named %s\n", bp);
403          continue;
404       }
405
406       /*
407        * First see how long the value is for the extended attribute.
408        */
409       xattr_value_len = lgetea(jcr->last_fname, bp, NULL, 0);
410       if (xattr_value_len < 0) {
411          berrno be;
412          if (errno == ENOENT || errno == EFORMAT) {
413             retval = bxattr_rtn_ok;
414          } else {
415             Mmsg2(jcr->errmsg, _("XATTR lgetea error on file \"%s\": ERR=%s\n"),
416                   jcr->last_fname, be.bstrerror());
417             Dmsg1(100, "%s", jcr->errmsg);
418          }
419          goto get_out;
420       }
421
422       /*
423        * Each xattr valuepair starts with a magic so we can restore it easier.
424        */
425       current_xattr = (xattr_t *)malloc(sizeof(xattr_t));
426       memset(current_xattr, 0, sizeof(xattr_t));
427       current_xattr->magic = XATTR_MAGIC;
428       expected_serialize_len += sizeof(current_xattr->magic);
429
430       /*
431        * Allocate space for storing the name.
432        */
433       current_xattr->name_length = name_length;
434       current_xattr->name = (char *)malloc(current_xattr->name_length);
435       memcpy(current_xattr->name, bp, current_xattr->name_length);
436
437       expected_serialize_len += sizeof(current_xattr->name_length) +
438                                 current_xattr->name_length;
439
440       if (xattr_value_len == 0) {
441          current_xattr->value = NULL;
442          current_xattr->value_length = 0;
443          expected_serialize_len += sizeof(current_xattr->value_length);
444       } else {
445          /*
446           * Allocate space for storing the value.
447           */
448          current_xattr->value = (char *)malloc(xattr_value_len);
449          memset(current_xattr->value, 0, xattr_value_len);
450
451          xattr_value_len = lgetea(jcr->last_fname, bp, current_xattr->value, xattr_value_len);
452          if (xattr_value_len < 0) {
453             berrno be;
454             if (errno == ENOENT || errno == EFORMAT) {
455                retval = bxattr_rtn_ok;
456             } else {
457                Mmsg2(jcr->errmsg, _("XATTR lgetea error on file \"%s\": ERR=%s\n"),
458                      jcr->last_fname, be.bstrerror());
459                Dmsg1(100, "%s", jcr->errmsg);
460             }
461
462             /*
463              * Default failure path out when retrieval of attr fails.
464              */
465             free(current_xattr->value);
466             free(current_xattr->name);
467             free(current_xattr);
468             goto get_out;
469          }
470          /*
471           * Store the actual length of the value.
472           */
473          current_xattr->value_length = xattr_value_len;
474          expected_serialize_len += sizeof(current_xattr->value_length) +
475                                    current_xattr->value_length;
476       }
477
478       if (xattr_value_list == NULL) {
479          xattr_value_list = New(alist(10, not_owned_by_alist));
480       }
481
482       xattr_value_list->append(current_xattr);
483       xattr_count++;
484
485       /*
486        * Protect ourself against things getting out of hand.
487        */
488       if (expected_serialize_len >= MAX_XATTR_LENGTH) {
489          Mmsg2(jcr->errmsg,
490                _("Xattr stream on file \"%s\" exceeds maximum size of %d bytes\n"),
491                jcr->last_fname, MAX_XATTR_LENGTH);
492          goto get_out;
493       }
494    }
495
496    free(xattr_list);
497    xattr_list = (char *)NULL;
498
499    /*
500     * If we found any xattr send them to the SD.
501     */
502    if (xattr_count > 0) {
503       /* Serialize the datastream. */
504       if (serialize_xattr_stream(jcr, expected_serialize_len,
505                                  xattr_value_list) < expected_serialize_len) {
506          Mmsg1(jcr->errmsg, _("Failed to serialize extended attributes on file \"%s\"\n"),
507                jcr->last_fname);
508          Dmsg1(100, "%s", jcr->errmsg);
509          goto get_out;
510       }
511
512       /*
513        * Send the datastream to the SD.
514        */
515       retval = send_xattr_stream(jcr, os_default_xattr_streams[0]);
516    } else {
517       retval = bxattr_rtn_ok;
518    }
519
520 get_out:
521    if (xattr_list != NULL) {
522       free(xattr_list);
523    }
524    if (xattr_value_list != NULL) {
525       xattr_drop_internal_table(xattr_value_list);
526    }
527
528    return retval;
529 }
530
531 static bxattr_rtn_code aix_restore_xattr_streams(JCR *jcr, int stream, char *content,
532                                                uint32_t content_length)
533 {
534    xattr_t *current_xattr;
535    alist *xattr_value_list;
536    bxattr_rtn_code retval = bxattr_rtn_error;
537
538    xattr_value_list = New(alist(10, not_owned_by_alist));
539
540    if (unserialize_xattr_stream(jcr, content, content_length,
541                                 xattr_value_list) != bxattr_rtn_ok) {
542       goto get_out;
543    }
544
545    foreach_alist(current_xattr, xattr_value_list) {
546       if (lsetea(jcr->last_fname, current_xattr->name, current_xattr->value,
547                  current_xattr->value_length, 0) != 0) {
548          berrno be;
549          switch (errno) {
550          case ENOENT:
551          case EFORMAT:
552             break;
553          case ENOTSUP:
554             /*
555              * If the filesystem reports it doesn't support XATTRs we clear
556              * the BXATTR_FLAG_RESTORE_NATIVE flag so we skip XATTR restores
557              * on all other files on the same filesystem. The
558              * BXATTR_FLAG_RESTORE_NATIVE flags gets sets again when we
559              * change from one filesystem to an other.
560              */
561             jcr->xattr_ctx->flags &= ~BXATTR_FLAG_RESTORE_NATIVE;
562             /* Failback wanted */
563          default:
564             MmsgD2(100, jcr->errmsg,
565                    _("XATTR lsetea error on file \"%s\": ERR=%s\n"),
566                    jcr->last_fname, be.bstrerror());
567             break;
568          }
569          goto get_out;
570       }
571    }
572    retval = bxattr_rtn_ok;
573
574 get_out:
575    xattr_drop_internal_table(xattr_value_list);
576
577    return retval;
578 }
579
580 /*
581  * Function pointers to the build and restore function to use for these xattrs.
582  */
583 static bxattr_rtn_code (*os_backup_xattr_streams)
584                         (JCR *jcr, FF_PKT *ff_pkt) =
585                         aix_xattr_build_streams;
586 static bxattr_rtn_code (*os_restore_xattr_streams)
587                         (JCR *jcr, int stream, char *content, uint32_t content_length) =
588                         aix_restore_xattr_streams;
589
590 #elif defined(HAVE_IRIX_OS)
591
592 #include <sys/attributes.h>
593
594 /*
595  * Define the supported XATTR streams for this OS
596  */
597 static int os_default_xattr_streams[1] = {
598    STREAM_XATTR_IRIX
599 };
600 static const char *xattr_acl_skiplist[1] = {
601    NULL
602 };
603 static const char *xattr_skiplist[1] = {
604    NULL
605 };
606
607 struct xattr_naming_space {
608    const char *name;
609    int flags;
610 };
611
612 static xattr_naming_space xattr_naming_spaces[] = {
613    {
614       "user.",
615       ATTR_DONTFOLLOW
616    }, {
617       "root.",
618       ATTR_ROOT | ATTR_DONTFOLLOW
619    }, {
620       NULL,
621       0
622    }
623 };
624
625 static bxattr_rtn_code irix_xattr_build_streams(JCR *jcr, FF_PKT *ff_pkt)
626 {
627    char dummy[32];
628    int cnt, length, xattr_count = 0;
629    attrlist_cursor_t cursor;
630    attrlist_t *attrlist;
631    attrlist_ent_t *attrlist_ent;
632    xattr_t *current_xattr;
633    alist *xattr_value_list = NULL;
634    uint32_t expected_serialize_len = 0;
635    bxattr_rtn_code retval = bxattr_rtn_error;
636    POOLMEM *xattrbuf = get_memory(ATTR_MAX_VALUELEN);
637
638    for (cnt = 0; xattr_naming_spaces[cnt].name != NULL; cnt++) {
639       memset(&cursor, 0, sizeof(attrlist_cursor_t));
640       for ( ;; } {
641          if (attr_list(jcr->last_fname, xattrbuf, ATTR_MAX_VALUELEN,
642                        xattr_naming_spaces[cnt].flags, &cursor) != 0) {
643             berrno be;
644             switch (errno) {
645             case ENOENT:
646                retval = bxattr_rtn_ok;
647                goto get_out;
648             default:
649                Mmsg2(jcr->errmsg, _("XATTR attr_list error on file \"%s\": ERR=%s\n"),
650                      jcr->last_fname, be.bstrerror());
651                Dmsg1(100, "%s", jcr->errmsg);
652                goto get_out;
653             }
654          }
655
656          attrlist = (attrlist_t *)xattrbuf;
657
658          /*
659           * Walk the available attributes.
660           */
661          for (cnt = 0; cnt < attrlist->al_count; cnt++) {
662             attrlist_ent = ATTR_ENTRY(xattrbuf, cnt);
663
664             /*
665              * First determine if we can retrieve the xattr and how big it really is.
666              */
667             length = sizeof(dummy);
668             if (attr_get(jcr->last_fname, attrlist_ent->a_name, dummy,
669                          &length, xattr_naming_spaces[cnt].flags) != 0) {
670                berrno be;
671                switch (errno) {
672                case ENOENT:
673                case ENOATTR:
674                   retval = bxattr_rtn_ok;
675                   goto get_out;
676                case E2BIG:
677                   /*
678                    * Size of the xattr is bigger then the 32 bytes dummy which is
679                    * likely. As length now contains its actual length we can allocate
680                    * a properly size buffer for the real retrieval.
681                    */
682                   break;
683                default:
684                   Mmsg2(jcr->errmsg, _("XATTR attr_list error on file \"%s\": ERR=%s\n"),
685                         jcr->last_fname, be.bstrerror());
686                   Dmsg1(100, "%s", jcr->errmsg);
687                   goto get_out;
688                }
689             }
690
691             /*
692              * Each xattr valuepair starts with a magic so we can restore it easier.
693              */
694             current_xattr = (xattr_t *)malloc(sizeof(xattr_t));
695             memset(current_xattr, 0, sizeof(xattr_t));
696             current_xattr->magic = XATTR_MAGIC;
697             expected_serialize_len += sizeof(current_xattr->magic);
698
699             /*
700              * Allocate space for storing the name.
701              * We store the name as <naming_space_name><xattr_name>
702              */
703             current_xattr->name_length = strlen(xattr_naming_spaces[cnt].name) +
704                                          strlen(attrlist_ent->a_name) + 1;
705             current_xattr->name = (char *)malloc(current_xattr->name_length);
706             bsnprintf(current_xattr->name, current_xattr->name_length, "%s%s",
707                       xattr_naming_spaces[cnt].name, attrlist_ent->a_name);
708
709             expected_serialize_len += sizeof(current_xattr->name_length) +
710                                       current_xattr->name_length;
711
712             current_xattr->value_length = length;
713             current_xattr->value = (char *)malloc(current_xattr->value_length);
714
715             /*
716              * Retrieve the actual value of the xattr.
717              */
718             if (attr_get(jcr->last_fname, attrlist_ent->a_name, current_xattr->value,
719                          &length, xattr_naming_spaces[cnt].flags) != 0) {
720                berrno be;
721
722                switch (errno) {
723                case ENOENT:
724                case ENOATTR:
725                   retval = bxattr_rtn_ok;
726                   break;
727                case E2BIG:
728                   /*
729                    * The buffer for the xattr isn't big enough. the value of
730                    * current_xattr->value_length is updated with the actual size
731                    * of the xattr. So we free the old buffer and create a new one
732                    * and try again. Normally this cannot happen as we size the
733                    * buffer using a call to attr_get before but in case of an
734                    * race condition it might happen.
735                    */
736                   free(current_xattr->value);
737                   current_xattr->value = (char *)malloc(length);
738                   if (attr_get(jcr->last_fname, attrlist_ent->a_name, current_xattr->value,
739                                &length, xattr_naming_spaces[cnt].flags) != 0) {
740                      switch (errno) {
741                      case ENOENT:
742                      case ENOATTR:
743                         retval = bxattr_rtn_ok;
744                         break;
745                      default:
746                         Mmsg2(jcr->errmsg,
747                               _("attr_list error on file \"%s\": ERR=%s\n"),
748                               jcr->last_fname, be.bstrerror(errno));
749                         Dmsg2(100, "attr_list error file=%s ERR=%s\n",
750                               jcr->last_fname, be.bstrerror());
751                         break;
752                      }
753                   } else {
754                      goto ok_continue;
755                   }
756                   break;
757                default:
758                   Mmsg2(jcr->errmsg, _("XATTR attr_list error on file \"%s\": ERR=%s\n"),
759                         jcr->last_fname, be.bstrerror());
760                   Dmsg1(100, "%s", jcr->errmsg);
761                   break;
762                }
763
764                /*
765                 * Default failure path out when retrieval of attr fails.
766                 */
767                free(current_xattr->value);
768                free(current_xattr->name);
769                free(current_xattr);
770                goto get_out;
771             }
772
773 ok_continue:
774             current_xattr->value_length = length;
775             expected_serialize_len += sizeof(current_xattr->value_length) +
776                                       current_xattr->value_length;
777
778             if (xattr_value_list == NULL) {
779                xattr_value_list = New(alist(10, not_owned_by_alist));
780             }
781
782             xattr_value_list->append(current_xattr);
783             xattr_count++;
784
785             /*
786              * Protect ourself against things getting out of hand.
787              */
788             if (expected_serialize_len >= MAX_XATTR_LENGTH) {
789                Mmsg2(jcr->errmsg,
790                      _("XATTR stream on file \"%s\" exceeds maximum size of %d bytes\n"),
791                      jcr->last_fname, MAX_XATTR_LENGTH);
792                goto get_out;
793             }
794          }
795
796          /*
797           * See if there are more attributes available for a next run of attr_list.
798           */
799          if (attrlist->al_more == 0) {
800             break;
801          }
802       }
803    }
804
805    /*
806     * If we found any xattr send them to the SD.
807     */
808    if (xattr_count > 0) {
809       /* Serialize the XATTR */
810       if (serialize_xattr_stream(jcr, expected_serialize_len,
811                                  xattr_value_list) < expected_serialize_len) {
812          Mmsg1(jcr->errmsg, _("Failed to serialize extended attributes on file \"%s\"\n"),
813                jcr->last_fname);
814          Dmsg1(100, "%s", jcr->errmsg);
815          goto get_out;
816       }
817
818       /* Send the XATTR to the SD. */
819       retval = send_xattr_stream(jcr, os_default_xattr_streams[0]);
820    } else {
821       retval = bxattr_rtn_ok;
822    }
823
824 get_out:
825    free_pool_memory(xattrbuf);
826
827    if (xattr_value_list != NULL) {
828       xattr_drop_internal_table(xattr_value_list);
829    }
830
831    return retval;
832 }
833
834 static bxattr_rtn_code irix_restore_xattr_streams(JCR *jcr,
835                                                  int stream,
836                                                  char *content,
837                                                  uint32_t content_length)
838 {
839    char *bp;
840    int cnt, cmp_size, name_space_index, flags;
841    xattr_t *current_xattr;
842    alist *xattr_value_list;
843    bxattr_rtn_code retval = bxattr_rtn_error;
844
845    xattr_value_list = New(alist(10, not_owned_by_alist));
846
847    if (unserialize_xattr_stream(jcr,
848                                 content,
849                                 content_length,
850                                 xattr_value_list) != bxattr_rtn_ok) {
851       goto get_out;
852    }
853
854    foreach_alist(current_xattr, xattr_value_list) {
855       /*
856        * See to what namingspace this xattr belongs to.
857        */
858       name_space_index = 0;
859       for (cnt = 0; xattr_naming_spaces[cnt].name != NULL; cnt++) {
860          cmp_size = strlen(xattr_naming_spaces[cnt].name);
861          if (!strncasecmp(current_xattr->name,
862                           xattr_naming_spaces[cnt].name,
863                           cmp_size)) {
864             name_space_index = cnt;
865             break;
866          }
867       }
868
869       /*
870        * If we got a xattr that doesn't belong to an valid namespace complain.
871        */
872       if (name_space_index == 0) {
873          Mmsg2(jcr->errmsg,
874                _("Received invalid xattr named %s on file \"%s\"\n"),
875                current_xattr->name, jcr->last_fname);
876          Dmsg1(100, "%s", jcr->errmsg);
877          goto get_out;
878       }
879
880       /*
881        * Restore the xattr first try to create the attribute from scratch.
882        */
883       flags = xattr_naming_spaces[name_space_index].flags | ATTR_CREATE;
884       bp = strchr(current_xattr->name, '.');
885       if (attr_set(jcr->last_fname, ++bp, current_xattr->value,
886                    current_xattr->value_length, flags) != 0) {
887          berrno be;
888
889          switch (errno) {
890          case ENOENT:
891             retval = bxattr_rtn_ok;
892             goto get_out;
893          case EEXIST:
894             /*
895              * The xattr already exists we need to replace it.
896              */
897             flags = xattr_naming_spaces[name_space_index].flags | ATTR_REPLACE;
898             if (attr_set(jcr->last_fname, bp, current_xattr->value,
899                          current_xattr->value_length, flags) != 0) {
900                switch (errno) {
901                case ENOENT:
902                   retval = bxattr_rtn_ok;
903                   goto get_out;
904                default:
905                   Mmsg2(jcr->errmsg, _("attr_set error on file \"%s\": ERR=%s\n"),
906                         jcr->last_fname, be.bstrerror(errno));
907                   Dmsg1(100, "%s", jcr->errmsg);
908                   goto get_out;
909                }
910             }
911             break;
912          default:
913             Mmsg2(jcr->errmsg, _("attr_set error on file \"%s\": ERR=%s\n"),
914                   jcr->last_fname, be.bstrerror());
915             Dmsg1(100, "%s", jcr->errmsg);
916             goto get_out;
917          }
918       }
919    }
920
921    retval = bxattr_rtn_ok;
922
923 get_out:
924    xattr_drop_internal_table(xattr_value_list);
925
926    return retval;
927 }
928
929 /*
930  * Function pointers to the build and restore function to use for these xattrs.
931  */
932 static bxattr_rtn_code (*os_backup_xattr_streams)
933                         (JCR *jcr, FF_PKT *ff_pkt) =
934                         irix_xattr_build_streams;
935 static bxattr_rtn_code (*os_restore_xattr_streams)
936                         (JCR *jcr, int stream, char *content, uint32_t content_length) =
937                         irix_restore_xattr_streams;
938
939 #elif defined(HAVE_DARWIN_OS) || \
940       defined(HAVE_LINUX_OS) || \
941       defined(HAVE_HURD_OS)
942
943 #if (!defined(HAVE_LISTXATTR) && !defined(HAVE_LLISTXATTR)) || \
944     (!defined(HAVE_GETXATTR) && !defined(HAVE_LGETXATTR)) || \
945     (!defined(HAVE_SETXATTR) && !defined(HAVE_LSETXATTR))
946 #error "Missing full support for the XATTR functions."
947 #endif
948
949 #ifdef HAVE_SYS_XATTR_H
950 #include <sys/xattr.h>
951 #else
952 #error "Missing sys/xattr.h header file"
953 #endif
954
955 /*
956  * Define the supported XATTR streams for this OS
957  */
958 #if defined(HAVE_DARWIN_OS)
959 static int os_default_xattr_streams[1] = {
960    STREAM_XATTR_DARWIN
961 };
962 static const char *xattr_acl_skiplist[2] = {
963    "com.apple.system.Security",
964    NULL
965 };
966 static const char *xattr_skiplist[3] = {
967    "com.apple.system.extendedsecurity",
968    "com.apple.ResourceFork",
969    NULL
970 };
971 #elif defined(HAVE_LINUX_OS)
972 static int os_default_xattr_streams[1] = {
973    STREAM_XATTR_LINUX
974 };
975 static const char *xattr_acl_skiplist[3] = {
976    "system.posix_acl_access",
977    "system.posix_acl_default",
978    NULL
979 };
980 static const char *xattr_skiplist[1] = {
981    NULL
982 };
983 #elif defined(HAVE_HURD_OS)
984 static int os_default_xattr_streams[1] = {
985    STREAM_XATTR_HURD
986 };
987 static const char *xattr_acl_skiplist[1] = {
988    NULL
989 };
990 static const char *xattr_skiplist[1] = {
991    NULL
992 };
993 #endif
994
995 /*
996  * OSX doesn't have llistxattr, lgetxattr and lsetxattr but has
997  * listxattr, getxattr and setxattr with an extra options argument
998  * which mimics the l variants of the functions when we specify
999  * XATTR_NOFOLLOW as the options value.
1000  */
1001 #if defined(HAVE_DARWIN_OS)
1002    #define llistxattr(path, list, size) \
1003            listxattr((path), (list), (size), XATTR_NOFOLLOW)
1004    #define lgetxattr(path, name, value, size) \
1005            getxattr((path), (name), (value), (size), 0, XATTR_NOFOLLOW)
1006    #define lsetxattr(path, name, value, size, flags) \
1007            setxattr((path), (name), (value), (size), (flags), XATTR_NOFOLLOW)
1008 #else
1009    /*
1010     * Fallback to the non l-functions when those are not available.
1011     */
1012    #if defined(HAVE_GETXATTR) && !defined(HAVE_LGETXATTR)
1013    #define lgetxattr getxattr
1014    #endif
1015    #if defined(HAVE_SETXATTR) && !defined(HAVE_LSETXATTR)
1016    #define lsetxattr setxattr
1017    #endif
1018    #if defined(HAVE_LISTXATTR) && !defined(HAVE_LLISTXATTR)
1019    #define llistxattr listxattr
1020    #endif
1021 #endif
1022
1023 static bxattr_rtn_code generic_xattr_build_streams(JCR *jcr, FF_PKT *ff_pkt)
1024 {
1025    char *bp;
1026    bool skip_xattr;
1027    char *xattr_list = NULL;
1028    int cnt, xattr_count = 0;
1029    uint32_t name_length;
1030    int32_t xattr_list_len,
1031            xattr_value_len;
1032    uint32_t expected_serialize_len = 0;
1033    xattr_t *current_xattr;
1034    alist *xattr_value_list = NULL;
1035    bxattr_rtn_code retval = bxattr_rtn_error;
1036
1037    /*
1038     * First get the length of the available list with extended attributes.
1039     */
1040    xattr_list_len = llistxattr(jcr->last_fname, NULL, 0);
1041    switch (xattr_list_len) {
1042    case -1: {
1043       berrno be;
1044
1045       switch (errno) {
1046       case ENOENT:
1047          retval = bxattr_rtn_ok;
1048          goto get_out;
1049       case BXATTR_ENOTSUP:
1050          /*
1051           * If the filesystem reports it doesn't support XATTRs we clear
1052           * the BXATTR_FLAG_RESTORE_NATIVE flag so we skip XATTR restores
1053           * on all other files on the same filesystem. The
1054           * BXATTR_FLAG_RESTORE_NATIVE flags gets sets again when we
1055           * change from one filesystem to an other.
1056           */
1057          jcr->xattr_ctx->flags &= ~BXATTR_FLAG_SAVE_NATIVE;
1058          retval = bxattr_rtn_ok;
1059          goto get_out;
1060       default:
1061          Mmsg2(jcr->errmsg, _("llistxattr error on file \"%s\": ERR=%s\n"),
1062                jcr->last_fname, be.bstrerror());
1063          Dmsg1(100, "%s", jcr->errmsg);
1064          goto get_out;
1065       }
1066       break;
1067    }
1068    case 0:
1069       retval = bxattr_rtn_ok;
1070       goto get_out;
1071    default:
1072       break;
1073    }
1074
1075    /*
1076     * Allocate room for the extented attribute list.
1077     */
1078    xattr_list = (char *)malloc(xattr_list_len + 1);
1079    memset(xattr_list, 0, xattr_list_len + 1);
1080
1081    /*
1082     * Get the actual list of extended attributes names for a file.
1083     */
1084    xattr_list_len = llistxattr(jcr->last_fname, xattr_list, xattr_list_len);
1085    if (xattr_list_len < 0) {
1086       berrno be;
1087       if (errno == ENOENT) {
1088          retval = bxattr_rtn_ok;
1089       } else {
1090          Mmsg2(jcr->errmsg, _("llistxattr error on file \"%s\": ERR=%s\n"),
1091                jcr->last_fname, be.bstrerror());
1092          Dmsg1(100, "%s", jcr->errmsg);
1093       }
1094      goto get_out;
1095    }
1096    xattr_list[xattr_list_len] = '\0';
1097
1098    /*
1099     * Walk the list of extended attributes names and retrieve the data.
1100     * We already count the bytes needed for serializing the stream later on.
1101     */
1102    for (bp = xattr_list;
1103        (bp - xattr_list) + 1 < xattr_list_len;
1104         bp = strchr(bp, '\0') + 1) {
1105       skip_xattr = false;
1106
1107       /*
1108        * On some OSes you also get the acls in the extented attribute list.
1109        * So we check if we are already backing up acls and if we do we
1110        * don't store the extended attribute with the same info.
1111        */
1112       if (ff_pkt->flags & FO_ACL) {
1113          for (cnt = 0; xattr_acl_skiplist[cnt] != NULL; cnt++) {
1114             if (bstrcmp(bp, xattr_acl_skiplist[cnt])) {
1115                skip_xattr = true;
1116                break;
1117             }
1118          }
1119       }
1120
1121       /*
1122        * On some OSes we want to skip certain xattrs which are in the xattr_skiplist array.
1123        */
1124       if (!skip_xattr) {
1125          for (cnt = 0; xattr_skiplist[cnt] != NULL; cnt++) {
1126             if (bstrcmp(bp, xattr_skiplist[cnt])) {
1127                skip_xattr = true;
1128                break;
1129             }
1130          }
1131       }
1132
1133       name_length = strlen(bp);
1134       if (skip_xattr || name_length == 0) {
1135          Dmsg1(100, "Skipping xattr named %s\n", bp);
1136          continue;
1137       }
1138
1139       /*
1140        * First see how long the value is for the extended attribute.
1141        */
1142       xattr_value_len = lgetxattr(jcr->last_fname, bp, NULL, 0);
1143       if (xattr_value_len < 0) {
1144          berrno be;
1145          if (errno == ENOENT) {
1146             retval = bxattr_rtn_ok;
1147          } else {
1148             Mmsg2(jcr->errmsg, _("lgetxattr error on file \"%s\": ERR=%s\n"),
1149                   jcr->last_fname, be.bstrerror());
1150             Dmsg1(100, "%s", jcr->errmsg);
1151          }
1152          goto get_out;
1153       }
1154
1155       /*
1156        * Each xattr valuepair starts with a magic so we can restore it easier.
1157        */
1158       current_xattr = (xattr_t *)malloc(sizeof(xattr_t));
1159       current_xattr->magic = XATTR_MAGIC;
1160       current_xattr->value = NULL;
1161       expected_serialize_len += sizeof(current_xattr->magic);
1162
1163       /*
1164        * Allocate space for storing the name.
1165        */
1166       current_xattr->name_length = name_length;
1167       current_xattr->name = (char *)malloc(current_xattr->name_length);
1168       memcpy(current_xattr->name, bp, current_xattr->name_length);
1169
1170       expected_serialize_len += sizeof(current_xattr->name_length) + current_xattr->name_length;
1171
1172       switch (xattr_value_len) {
1173       case 0:
1174          current_xattr->value = NULL;
1175          current_xattr->value_length = 0;
1176          expected_serialize_len += sizeof(current_xattr->value_length);
1177          break;
1178       default:
1179          /*
1180           * Allocate space for storing the value.
1181           */
1182          current_xattr->value = (char *)malloc(xattr_value_len);
1183          memset(current_xattr->value, 0, xattr_value_len);
1184
1185          xattr_value_len = lgetxattr(jcr->last_fname, bp, current_xattr->value, xattr_value_len);
1186          if (xattr_value_len < 0) {
1187             berrno be;
1188
1189             switch (errno) {
1190             case ENOENT:
1191                retval = bxattr_rtn_ok;
1192                break;
1193             default:
1194                Mmsg2(jcr->errmsg, _("lgetxattr error on file \"%s\": ERR=%s\n"),
1195                      jcr->last_fname, be.bstrerror());
1196                Dmsg1(100, "%s", jcr->errmsg);
1197                break;
1198             }
1199
1200             /*
1201              * Default failure path out when retrieval of attr fails.
1202              */
1203             free(current_xattr->value);
1204             free(current_xattr->name);
1205             free(current_xattr);
1206             goto get_out;
1207          }
1208
1209          /*
1210           * Store the actual length of the value.
1211           */
1212          current_xattr->value_length = xattr_value_len;
1213          expected_serialize_len += sizeof(current_xattr->value_length) + current_xattr->value_length;
1214          break;
1215       }
1216
1217       if (xattr_value_list == NULL) {
1218          xattr_value_list = New(alist(10, not_owned_by_alist));
1219       }
1220
1221       xattr_value_list->append(current_xattr);
1222       xattr_count++;
1223
1224       /*
1225        * Protect ourself against things getting out of hand.
1226        */
1227       if (expected_serialize_len >= MAX_XATTR_LENGTH) {
1228          Mmsg2(jcr->errmsg,
1229                _("Xattr stream on file \"%s\" exceeds maximum size of %d bytes\n"),
1230                jcr->last_fname, MAX_XATTR_LENGTH);
1231          goto get_out;
1232       }
1233    }
1234
1235    free(xattr_list);
1236    xattr_list = (char *)NULL;
1237
1238    /*
1239     * If we found any xattr send them to the SD.
1240     */
1241    if (xattr_count > 0) {
1242       /*
1243        * Serialize the datastream.
1244        */
1245       if (serialize_xattr_stream(jcr, expected_serialize_len,
1246                                  xattr_value_list) < expected_serialize_len) {
1247          Mmsg1(jcr->errmsg, _("Failed to serialize extended attributes on file \"%s\"\n"),
1248                jcr->last_fname);
1249          Dmsg1(100, "%s", jcr->errmsg);
1250          goto get_out;
1251       }
1252
1253       /*
1254        * Send the datastream to the SD.
1255        */
1256       retval = send_xattr_stream(jcr, os_default_xattr_streams[0]);
1257    } else {
1258       retval = bxattr_rtn_ok;
1259    }
1260
1261 get_out:
1262    if (xattr_list != NULL) {
1263       free(xattr_list);
1264    }
1265    if (xattr_value_list != NULL) {
1266       xattr_drop_internal_table(xattr_value_list);
1267    }
1268
1269    return retval;
1270 }
1271
1272 static bxattr_rtn_code generic_restore_xattr_streams(JCR *jcr, int stream,
1273                                                     char *content,
1274                                                     uint32_t content_length)
1275 {
1276    xattr_t *current_xattr;
1277    alist *xattr_value_list;
1278    bxattr_rtn_code retval = bxattr_rtn_error;
1279
1280    xattr_value_list = New(alist(10, not_owned_by_alist));
1281
1282    if (unserialize_xattr_stream(jcr, content, content_length,
1283                                 xattr_value_list) != bxattr_rtn_ok) {
1284       goto get_out;
1285    }
1286
1287    foreach_alist(current_xattr, xattr_value_list) {
1288       if (lsetxattr(jcr->last_fname, current_xattr->name, current_xattr->value, current_xattr->value_length, 0) != 0) {
1289          berrno be;
1290          if (errno == ENOENT) {
1291             goto get_out;
1292          } else if (errno == BXATTR_ENOTSUP) {
1293             /*
1294              * If the filesystem reports it doesn't support XATTRs we clear
1295              * the BXATTR_FLAG_RESTORE_NATIVE flag so we skip XATTR restores
1296              * on all other files on the same filesystem. The
1297              * BXATTR_FLAG_RESTORE_NATIVE flags gets sets again when we
1298              * change from one filesystem to an other.
1299              */
1300             jcr->xattr_ctx->flags &= ~BXATTR_FLAG_RESTORE_NATIVE;
1301          }
1302          MmsgD2(100, jcr->errmsg,
1303                 _("lsetxattr error on file \"%s\": ERR=%s\n"),
1304                 jcr->last_fname, be.bstrerror());
1305          goto get_out;
1306       }
1307    }
1308
1309    retval = bxattr_rtn_ok;
1310
1311 get_out:
1312    xattr_drop_internal_table(xattr_value_list);
1313    return retval;
1314 }
1315
1316 /*
1317  * Function pointers to the build and restore functions to use for these xattrs.
1318  */
1319 static bxattr_rtn_code (*os_backup_xattr_streams)
1320                         (JCR *jcr, FF_PKT *ff_pkt) =
1321                         generic_xattr_build_streams;
1322 static bxattr_rtn_code (*os_restore_xattr_streams)
1323                         (JCR *jcr, int stream, char *content, uint32_t content_length) =
1324                         generic_restore_xattr_streams;
1325
1326 #elif defined(HAVE_FREEBSD_OS) || \
1327       defined(HAVE_NETBSD_OS) || \
1328       defined(HAVE_OPENBSD_OS)
1329
1330 #if (!defined(HAVE_EXTATTR_GET_LINK) && !defined(HAVE_EXTATTR_GET_FILE)) || \
1331     (!defined(HAVE_EXTATTR_SET_LINK) && !defined(HAVE_EXTATTR_SET_FILE)) || \
1332     (!defined(HAVE_EXTATTR_LIST_LINK) && !defined(HAVE_EXTATTR_LIST_FILE)) || \
1333     !defined(HAVE_EXTATTR_NAMESPACE_TO_STRING) || \
1334     !defined(HAVE_EXTATTR_STRING_TO_NAMESPACE)
1335 #error "Missing full support for the extattr functions."
1336 #endif
1337
1338 #ifdef HAVE_SYS_EXTATTR_H
1339 #include <sys/extattr.h>
1340 #else
1341 #error "Missing sys/extattr.h header file"
1342 #endif
1343
1344 #ifdef HAVE_LIBUTIL_H
1345 #include <libutil.h>
1346 #endif
1347
1348 #if !defined(HAVE_EXTATTR_GET_LINK) && defined(HAVE_EXTATTR_GET_FILE)
1349 #define extattr_get_link extattr_get_file
1350 #endif
1351 #if !defined(HAVE_EXTATTR_SET_LINK) && defined(HAVE_EXTATTR_SET_FILE)
1352 #define extattr_set_link extattr_set_file
1353 #endif
1354 #if !defined(HAVE_EXTATTR_LIST_LINK) && defined(HAVE_EXTATTR_LIST_FILE)
1355 #define extattr_list_link extattr_list_file
1356 #endif
1357
1358 #if defined(HAVE_FREEBSD_OS)
1359 static int os_default_xattr_streams[1] = {
1360    STREAM_XATTR_FREEBSD
1361 };
1362 static int os_default_xattr_namespaces[2] = {
1363    EXTATTR_NAMESPACE_USER,
1364    EXTATTR_NAMESPACE_SYSTEM
1365 };
1366 static const char *xattr_acl_skiplist[4] = {
1367    "system.posix1e.acl_access",
1368    "system.posix1e.acl_default",
1369    "system.nfs4.acl",
1370    NULL
1371 };
1372 static const char *xattr_skiplist[1] = {
1373    NULL
1374 };
1375 #elif defined(HAVE_NETBSD_OS)
1376 static int os_default_xattr_streams[1] = {
1377    STREAM_XATTR_NETBSD
1378 };
1379 static int os_default_xattr_namespaces[2] = {
1380    EXTATTR_NAMESPACE_USER,
1381    EXTATTR_NAMESPACE_SYSTEM
1382 };
1383 static const char *xattr_acl_skiplist[1] = {
1384    NULL
1385 };
1386 static const char *xattr_skiplist[1] = {
1387    NULL
1388 };
1389 #elif defined(HAVE_OPENBSD_OS)
1390 static int os_default_xattr_streams[1] = {
1391    STREAM_XATTR_OPENBSD
1392 };
1393 static int os_default_xattr_namespaces[2] = {
1394    EXTATTR_NAMESPACE_USER,
1395    EXTATTR_NAMESPACE_SYSTEM
1396 };
1397 static const char *xattr_acl_skiplist[1] = {
1398    NULL
1399 };
1400 static const char *xattr_skiplist[1] = {
1401    NULL
1402 };
1403 #endif
1404
1405 static bxattr_rtn_code bsd_backup_xattr_streams(JCR *jcr, FF_PKT *ff_pkt)
1406 {
1407    bool skip_xattr;
1408    char *xattr_list = NULL;
1409    int cnt, index, xattr_count = 0;
1410    int32_t xattr_list_len,
1411            xattr_value_len;
1412    uint32_t expected_serialize_len = 0;
1413    unsigned int namespace_index;
1414    int attrnamespace;
1415    char *current_attrnamespace = NULL;
1416    char current_attrname[XATTR_BUFSIZ], current_attrtuple[XATTR_BUFSIZ];
1417    xattr_t *current_xattr;
1418    alist *xattr_value_list = NULL;
1419    bxattr_rtn_code retval = bxattr_rtn_error;
1420
1421    /*
1422     * Loop over all available xattr namespaces.
1423     */
1424    for (namespace_index = 0;
1425         namespace_index < sizeof(os_default_xattr_namespaces) / sizeof(int);
1426         namespace_index++) {
1427       attrnamespace = os_default_xattr_namespaces[namespace_index];
1428
1429       /*
1430        * First get the length of the available list with extended attributes.
1431        * If we get EPERM on system namespace, don't return error.
1432        * This is expected for normal users trying to archive the system
1433        * namespace on FreeBSD 6.2 and later. On NetBSD 3.1 and later,
1434        * they've decided to return EOPNOTSUPP instead.
1435        */
1436       xattr_list_len = extattr_list_link(jcr->last_fname, attrnamespace, NULL, 0);
1437       switch (xattr_list_len) {
1438       case -1: {
1439          berrno be;
1440
1441          switch (errno) {
1442          case ENOENT:
1443             retval = bxattr_rtn_ok;
1444             goto get_out;
1445 #if defined(EOPNOTSUPP)
1446          case EOPNOTSUPP:
1447 #endif
1448          case EPERM:
1449             if (attrnamespace == EXTATTR_NAMESPACE_SYSTEM) {
1450                continue;
1451             }
1452             /*
1453              * FALLTHROUGH
1454              */
1455          default:
1456             Mmsg2(jcr->errmsg, _("extattr_list_link error on file \"%s\": ERR=%s\n"),
1457                   jcr->last_fname, be.bstrerror());
1458             Dmsg1(100, "%s", jcr->errmsg);
1459             goto get_out;
1460          }
1461          break;
1462       }
1463       case 0:
1464          continue;
1465       default:
1466          break;
1467       }
1468
1469       /*
1470        * Allocate room for the extented attribute list.
1471        */
1472       xattr_list = (char *)malloc(xattr_list_len + 1);
1473       memset(xattr_list, 0, xattr_list_len + 1);
1474
1475       /*
1476        * Get the actual list of extended attributes names for a file.
1477        */
1478       xattr_list_len = extattr_list_link(jcr->last_fname, attrnamespace,
1479                                          xattr_list, xattr_list_len);
1480       if (xattr_list_len < 0) {
1481          berrno be;
1482          if (errno == ENOENT) {
1483             retval = bxattr_rtn_ok;
1484          } else {
1485             Mmsg2(jcr->errmsg, _("extattr_list_link error on file \"%s\": ERR=%s\n"),
1486                   jcr->last_fname, be.bstrerror());
1487             Dmsg1(100, "%s", jcr->errmsg);
1488          }
1489          goto get_out;
1490       }
1491       xattr_list[xattr_list_len] = '\0';
1492
1493       /*
1494        * Convert the numeric attrnamespace into a string representation and make
1495        * a private copy of that string. The extattr_namespace_to_string functions
1496        * returns a strdupped string which we need to free.
1497        */
1498       if (extattr_namespace_to_string(attrnamespace, &current_attrnamespace) != 0) {
1499          Mmsg2(jcr->errmsg, _("Failed to convert %d into namespace on file \"%s\"\n"),
1500                attrnamespace, jcr->last_fname);
1501          Dmsg1(100, "%s", jcr->errmsg);
1502          goto get_out;
1503       }
1504
1505       /*
1506        * Walk the list of extended attributes names and retrieve the data.
1507        * We already count the bytes needed for serializing the stream later on.
1508        */
1509       for (index = 0; index < xattr_list_len; index += xattr_list[index] + 1) {
1510          skip_xattr = false;
1511
1512          /*
1513           * Print the current name into the buffer as its not null terminated
1514           * we need to use the length encoded in the string for copying only
1515           * the needed bytes.
1516           */
1517          cnt = xattr_list[index];
1518          if (cnt > ((int)sizeof(current_attrname) - 1)) {
1519             cnt = ((int)sizeof(current_attrname) - 1);
1520          }
1521          strncpy(current_attrname, xattr_list + (index + 1), cnt);
1522          current_attrname[cnt] = '\0';
1523
1524          /*
1525           * First make a xattr tuple of the current namespace and the name of
1526           * the xattr. e.g. something like user.<attrname> or system.<attrname>
1527           */
1528          bsnprintf(current_attrtuple, sizeof(current_attrtuple), "%s.%s",
1529                    current_attrnamespace, current_attrname);
1530
1531          /*
1532           * On some OSes you also get the acls in the extented attribute list.
1533           * So we check if we are already backing up acls and if we do we
1534           * don't store the extended attribute with the same info.
1535           */
1536          if (ff_pkt->flags & FO_ACL) {
1537             for (cnt = 0; xattr_acl_skiplist[cnt] != NULL; cnt++) {
1538                if (bstrcmp(current_attrtuple, xattr_acl_skiplist[cnt])) {
1539                   skip_xattr = true;
1540                   break;
1541                }
1542             }
1543          }
1544
1545          /*
1546           * On some OSes we want to skip certain xattrs which are in the
1547           * xattr_skiplist array.
1548           */
1549          if (!skip_xattr) {
1550             for (cnt = 0; xattr_skiplist[cnt] != NULL; cnt++) {
1551                if (bstrcmp(current_attrtuple, xattr_skiplist[cnt])) {
1552                   skip_xattr = true;
1553                   break;
1554                }
1555             }
1556          }
1557
1558          if (skip_xattr) {
1559             Dmsg1(100, "Skipping xattr named %s\n", current_attrname);
1560             continue;
1561          }
1562
1563          /*
1564           * First see how long the value is for the extended attribute.
1565           */
1566          xattr_value_len = extattr_get_link(jcr->last_fname, attrnamespace,
1567                                             current_attrname, NULL, 0);
1568          switch (xattr_value_len) {
1569          case -1: {
1570             berrno be;
1571
1572             switch (errno) {
1573             case ENOENT:
1574                retval = bxattr_rtn_ok;
1575                goto get_out;
1576             default:
1577                Mmsg2(jcr->errmsg, _("extattr_get_link error on file \"%s\": ERR=%s\n"),
1578                      jcr->last_fname, be.bstrerror());
1579                Dmsg1(100, "%s", jcr->errmsg);
1580                goto get_out;
1581             }
1582             break;
1583          }
1584          default:
1585             break;
1586          }
1587
1588          /*
1589           * Each xattr valuepair starts with a magic so we can restore it easier.
1590           */
1591          current_xattr = (xattr_t *)malloc(sizeof(xattr_t));
1592          memset(current_xattr, 0, sizeof(xattr_t));
1593          current_xattr->magic = XATTR_MAGIC;
1594          expected_serialize_len += sizeof(current_xattr->magic);
1595
1596          /*
1597           * Allocate space for storing the name.
1598           */
1599          current_xattr->name_length = strlen(current_attrtuple);
1600          current_xattr->name = (char *)malloc(current_xattr->name_length);
1601          memcpy(current_xattr->name, current_attrtuple, current_xattr->name_length);
1602
1603          expected_serialize_len += sizeof(current_xattr->name_length) +
1604                                    current_xattr->name_length;
1605
1606          switch (xattr_value_len) {
1607          case 0:
1608             current_xattr->value = NULL;
1609             current_xattr->value_length = 0;
1610             expected_serialize_len += sizeof(current_xattr->value_length);
1611             break;
1612          default:
1613             /*
1614              * Allocate space for storing the value.
1615              */
1616             current_xattr->value = (char *)malloc(xattr_value_len);
1617             memset(current_xattr->value, 0, xattr_value_len);
1618
1619             xattr_value_len = extattr_get_link(jcr->last_fname, attrnamespace,
1620                                                current_attrname, current_xattr->value,
1621                                                xattr_value_len);
1622             if (xattr_value_len < 0) {
1623                berrno be;
1624
1625                switch (errno) {
1626                case ENOENT:
1627                   retval = bxattr_rtn_ok;
1628                   break;
1629                default:
1630                   Mmsg2(jcr->errmsg, _("extattr_get_link error on file \"%s\": ERR=%s\n"),
1631                         jcr->last_fname, be.bstrerror());
1632                   Dmsg1(100, "%s", jcr->errmsg);
1633                   break;
1634                }
1635
1636                /*
1637                 * Default failure path out when retrieval of attr fails.
1638                 */
1639                free(current_xattr->value);
1640                free(current_xattr->name);
1641                free(current_xattr);
1642                goto get_out;
1643             }
1644
1645             /*
1646              * Store the actual length of the value.
1647              */
1648             current_xattr->value_length = xattr_value_len;
1649             expected_serialize_len += sizeof(current_xattr->value_length) +
1650                                       current_xattr->value_length;
1651             break;
1652          }
1653
1654          if (xattr_value_list == NULL) {
1655             xattr_value_list = New(alist(10, not_owned_by_alist));
1656          }
1657
1658          xattr_value_list->append(current_xattr);
1659          xattr_count++;
1660
1661          /*
1662           * Protect ourself against things getting out of hand.
1663           */
1664          if (expected_serialize_len >= MAX_XATTR_LENGTH) {
1665             Mmsg2(jcr->errmsg, _("Xattr stream on file \"%s\" exceeds maximum size of %d bytes\n"),
1666                   jcr->last_fname, MAX_XATTR_LENGTH);
1667             Dmsg1(100, "%s", jcr->errmsg);
1668             goto get_out;
1669          }
1670       }
1671
1672       /*
1673        * Drop the local copy of the current_attrnamespace.
1674        */
1675       actuallyfree(current_attrnamespace);
1676       current_attrnamespace = NULL;
1677
1678       /*
1679        * We are done with this xattr list.
1680        */
1681       free(xattr_list);
1682       xattr_list = (char *)NULL;
1683    }
1684
1685    /*
1686     * If we found any xattr send them to the SD.
1687     */
1688    if (xattr_count > 0) {
1689       /*
1690        * Serialize the datastream.
1691        */
1692       if (serialize_xattr_stream(jcr,
1693                                  expected_serialize_len,
1694                                  xattr_value_list) < expected_serialize_len) {
1695          Mmsg1(jcr->errmsg, _("Failed to serialize extended attributes on file \"%s\"\n"),
1696                jcr->last_fname);
1697          Dmsg1(100, "%s", jcr->errmsg);
1698          goto get_out;
1699       }
1700
1701       /*
1702        * Send the datastream to the SD.
1703        */
1704       retval = send_xattr_stream(jcr, os_default_xattr_streams[0]);
1705    } else {
1706       retval = bxattr_rtn_ok;
1707    }
1708
1709 get_out:
1710    if (current_attrnamespace != NULL) {
1711       actuallyfree(current_attrnamespace);
1712    }
1713    if (xattr_list != NULL) {
1714       free(xattr_list);
1715    }
1716    if (xattr_value_list != NULL) {
1717       xattr_drop_internal_table(xattr_value_list);
1718    }
1719
1720    return retval;
1721 }
1722
1723 static bxattr_rtn_code bsd_restore_xattr_streams(JCR *jcr,
1724                                                 int stream,
1725                                                 char *content,
1726                                                 uint32_t content_length)
1727 {
1728    xattr_t *current_xattr;
1729    alist *xattr_value_list;
1730    int current_attrnamespace, cnt;
1731    char *attrnamespace, *attrname;
1732    bxattr_rtn_code retval = bxattr_rtn_error;
1733
1734    xattr_value_list = New(alist(10, not_owned_by_alist));
1735
1736    if (unserialize_xattr_stream(jcr,
1737                                 content,
1738                                 content_length,
1739                                 xattr_value_list) != bxattr_rtn_ok) {
1740       goto get_out;
1741    }
1742
1743    foreach_alist(current_xattr, xattr_value_list) {
1744       /*
1745        * Try splitting the xattr_name into a namespace and name part.
1746        * The splitting character is a .
1747        */
1748       attrnamespace = current_xattr->name;
1749       if ((attrname = strchr(attrnamespace, '.')) == (char *)NULL) {
1750          Mmsg2(jcr->errmsg, _("Failed to split %s into namespace and name part on file \"%s\"\n"),
1751                current_xattr->name, jcr->last_fname);
1752          Dmsg1(100, "%s", jcr->errmsg);
1753          goto get_out;
1754       }
1755       *attrname++ = '\0';
1756
1757       /*
1758        * Make sure the attrnamespace makes sense.
1759        */
1760       if (extattr_string_to_namespace(attrnamespace, &current_attrnamespace) != 0) {
1761          Mmsg2(jcr->errmsg, _("Failed to convert %s into namespace on file \"%s\"\n"),
1762                attrnamespace, jcr->last_fname);
1763          Dmsg1(100, "%s", jcr->errmsg);
1764          goto get_out;
1765       }
1766
1767       /*
1768        * Try restoring the extended attribute.
1769        */
1770       cnt = extattr_set_link(jcr->last_fname, current_attrnamespace,
1771                              attrname, current_xattr->value, current_xattr->value_length);
1772       if (cnt < 0 || cnt != (int)current_xattr->value_length) {
1773          berrno be;
1774          if (errno == ENOENT) {
1775             goto get_out;
1776          } else {
1777             Mmsg2(jcr->errmsg, _("extattr_set_link error on file \"%s\": ERR=%s\n"),
1778                   jcr->last_fname, be.bstrerror());
1779             Dmsg1(100, "%s", jcr->errmsg);
1780             goto get_out;
1781          }
1782       }
1783    }
1784
1785    retval = bxattr_rtn_ok;
1786
1787 get_out:
1788    xattr_drop_internal_table(xattr_value_list);
1789    return retval;
1790 }
1791
1792 /*
1793  * Function pointers to the build and restore function to use for these xattrs.
1794  */
1795 static bxattr_rtn_code (*os_backup_xattr_streams)
1796                         (JCR *jcr, FF_PKT *ff_pkt) =
1797                         bsd_backup_xattr_streams;
1798 static bxattr_rtn_code (*os_restore_xattr_streams)
1799                         (JCR *jcr, int stream, char *content, uint32_t content_length) =
1800                         bsd_restore_xattr_streams;
1801
1802 #elif defined(HAVE_OSF1_OS)
1803
1804 #if !defined(HAVE_GETPROPLIST) || \
1805     !defined(HAVE_GET_PROPLIST_ENTRY) || \
1806     !defined(HAVE_SIZEOF_PROPLIST_ENTRY) || \
1807     !defined(HAVE_ADD_PROPLIST_ENTRY) || \
1808     !defined(HAVE_SETPROPLIST)
1809 #error "Missing full support for the Extended Attributes functions."
1810 #endif
1811
1812 #ifdef HAVE_SYS_PROPLIST_H
1813 #include <sys/proplist.h>
1814 #else
1815 #error "Missing sys/proplist.h header file"
1816 #endif
1817
1818 /*
1819  * Define the supported XATTR streams for this OS
1820  */
1821 static int os_default_xattr_streams[1] = {
1822    STREAM_XATTR_TRU64
1823 };
1824 static const char *xattr_acl_skiplist[1] = {
1825    NULL
1826 };
1827 static const char *xattr_skiplist[1] = {
1828    NULL
1829 };
1830
1831 static bxattr_rtn_code tru64_backup_xattr_streams(JCR *jcr, FF_PKT *ff_pkt)
1832 {
1833    int cnt;
1834    char *bp,
1835         *xattr_name,
1836         *xattr_value;
1837    bool skip_xattr;
1838    int xattr_count = 0;
1839    int32_t *flags,
1840            *xattr_value_len;
1841    int32_t xattr_list_len,
1842            xattrbuf_size,
1843            xattrbuf_min_size;
1844    uint32_t expected_serialize_len = 0;
1845    xattr_t *current_xattr;
1846    alist *xattr_value_list = NULL;
1847    struct proplistname_args prop_args;
1848    bxattr_rtn_code retval = bxattr_rtn_error;
1849    POOLMEM *xattrbuf = get_pool_memory(PM_MESSAGE);
1850
1851    xattrbuf_size = sizeof_pool_memory(xattrbuf);
1852    xattrbuf_min_size = 0;
1853    xattr_list_len = getproplist(jcr->last_fname, 1, &prop_args, xattrbuf_size,
1854                                 xattrbuf, &xattrbuf_min_size);
1855
1856    /*
1857     * See what xattr are available.
1858     */
1859    switch (xattr_list_len) {
1860    case -1: {
1861       berrno be;
1862
1863       switch (errno) {
1864       case EOPNOTSUPP:
1865          /*
1866           * If the filesystem reports it doesn't support XATTRs we clear
1867           * the BXATTR_FLAG_RESTORE_NATIVE flag so we skip XATTR restores
1868           * on all other files on the same filesystem. The
1869           * BXATTR_FLAG_RESTORE_NATIVE flags gets sets again when we
1870           * change from one filesystem to an other.
1871           */
1872          jcr->xattr_ctx->flags &= ~BXATTR_FLAG_SAVE_NATIVE;
1873          retval = bxattr_rtn_ok;
1874          goto get_out;
1875       default:
1876          Mmsg2(jcr->errmsg, _("getproplist error on file \"%s\": ERR=%s\n"),
1877                jcr->last_fname, be.bstrerror());
1878          Dmsg1(100, "%s", jcr->errmsg);
1879          goto get_out;
1880       }
1881       break;
1882    }
1883    case 0:
1884       if (xattrbuf_min_size) {
1885          /*
1886           * The buffer isn't big enough to hold the xattr data, we now have
1887           * a minimum buffersize so we resize the buffer and try again.
1888           */
1889          xattrbuf = check_pool_memory_size(xattrbuf, xattrbuf_min_size + 1);
1890          xattrbuf_size = xattrbuf_min_size + 1;
1891          xattr_list_len = getproplist(jcr->last_fname, 1, &prop_args, xattrbuf_size,
1892                                    xattrbuf, &xattrbuf_min_size);
1893          switch (xattr_list_len) {
1894          case -1: {
1895             berrno be;
1896
1897             switch (errno) {
1898             default:
1899                Mmsg2(jcr->errmsg, _("getproplist error on file \"%s\": ERR=%s\n"),
1900                      jcr->last_fname, be.bstrerror());
1901                Dmsg1(100, "%s", jcr->errmsg);
1902                goto get_out;
1903             }
1904             break;
1905          }
1906          case 0:
1907             /*
1908              * This should never happen as we sized the buffer according to the minimumsize
1909              * returned by a previous getproplist call. If it does happen things are fishy and
1910              * we are better of forgetting this xattr as it seems its list is changing at this
1911              * exact moment so we can never make a good backup copy of it.
1912              */
1913             retval = bxattr_rtn_ok;
1914             goto get_out;
1915          default:
1916             break;
1917          }
1918       } else {
1919          /*
1920           * No xattr on file.
1921           */
1922          retval = bxattr_rtn_ok;
1923          goto get_out;
1924       }
1925       break;
1926    default:
1927       break;
1928    }
1929
1930    /*
1931     * Walk the list of extended attributes names and retrieve the data.
1932     * We already count the bytes needed for serializing the stream later on.
1933     */
1934    bp = xattrbuf;
1935    while (xattrbuf_size > 0) {
1936       /*
1937        * Call getproplist_entry to initialize name and value
1938        * pointers to entries position within buffer.
1939        */
1940       xattrbuf_size -= get_proplist_entry(&xattr_name, &flags, &xattr_value_len, &xattr_value, &bp);
1941
1942       /*
1943        * On some OSes you also get the acls in the extented attribute list.
1944        * So we check if we are already backing up acls and if we do we
1945        * don't store the extended attribute with the same info.
1946        */
1947       if (ff_pkt->flags & FO_ACL) {
1948          for (cnt = 0; xattr_acl_skiplist[cnt] != NULL; cnt++) {
1949             if (bstrcmp(xattr_name, xattr_acl_skiplist[cnt])) {
1950                skip_xattr = true;
1951                break;
1952             }
1953          }
1954       }
1955
1956       /*
1957        * On some OSes we want to skip certain xattrs which are in the xattr_skiplist array.
1958        */
1959       if (!skip_xattr) {
1960          for (cnt = 0; xattr_skiplist[cnt] != NULL; cnt++) {
1961             if (bstrcmp(xattr_name, xattr_skiplist[cnt])) {
1962                skip_xattr = true;
1963                break;
1964             }
1965          }
1966       }
1967
1968       if (skip_xattr) {
1969          Dmsg1(100, "Skipping xattr named %s\n", xattr_name);
1970          continue;
1971       }
1972
1973       /*
1974        * Each xattr valuepair starts with a magic so we can restore it easier.
1975        */
1976       current_xattr = (xattr_t *)malloc(sizeof(xattr_t));
1977       memset(current_xattr, 0, sizeof(xattr_t));
1978       current_xattr->magic = XATTR_MAGIC;
1979       expected_serialize_len += sizeof(current_xattr->magic);
1980
1981       current_xattr->name_length = strlen(xattr_name);
1982       current_xattr->name = bstrdup(xattr_name);
1983
1984       expected_serialize_len += sizeof(current_xattr->name_length) +
1985                                 current_xattr->name_length;
1986
1987       current_xattr->value_length = *xattr_value_len;
1988       current_xattr->value = (char *)malloc(current_xattr->value_length);
1989       memcpy(current_xattr->value, xattr_value, current_xattr->value_length);
1990
1991       expected_serialize_len += sizeof(current_xattr->value_length) +
1992                                 current_xattr->value_length;
1993
1994       if (xattr_value_list == NULL) {
1995          xattr_value_list = New(alist(10, not_owned_by_alist));
1996       }
1997
1998       xattr_value_list->append(current_xattr);
1999       xattr_count++;
2000
2001       /*
2002        * Protect ourself against things getting out of hand.
2003        */
2004       if (expected_serialize_len >= MAX_XATTR_LENGTH) {
2005          Mmsg2(jcr->errmsg,
2006                _("Xattr stream on file \"%s\" exceeds maximum size of %d bytes\n"),
2007                jcr->last_fname, MAX_XATTR_LENGTH);
2008          goto get_out;
2009       }
2010    }
2011
2012    /*
2013     * If we found any xattr send them to the SD.
2014     */
2015    if (xattr_count > 0) {
2016       /*
2017        * Serialize the datastream.
2018        */
2019       if (serialize_xattr_stream(jcr,
2020                                  expected_serialize_len,
2021                                  xattr_value_list) < expected_serialize_len) {
2022          Mmsg1(jcr->errmsg, _("Failed to serialize extended attributes on file \"%s\"\n"),
2023                jcr->last_fname);
2024          Dmsg1(100, "%s", jcr->errmsg);
2025          goto get_out;
2026       }
2027
2028       /*
2029        * Send the datastream to the SD.
2030        */
2031       retval = send_xattr_stream(jcr, os_default_xattr_streams[0]);
2032    } else {
2033       retval = bxattr_rtn_ok;
2034    }
2035
2036 get_out:
2037    if (xattr_value_list != NULL) {
2038       xattr_drop_internal_table(xattr_value_list);
2039    }
2040    free_pool_memory(xattrbuf);
2041
2042    return retval;
2043 }
2044
2045 static bxattr_rtn_code tru64_restore_xattr_streams(JCR *jcr,
2046                                                   int stream,
2047                                                   char *content,
2048                                                   uint32_t content_length)
2049 {
2050    char *bp, *xattrbuf = NULL;
2051    int32_t xattrbuf_size, cnt;
2052    xattr_t *current_xattr;
2053    alist *xattr_value_list;
2054    bxattr_rtn_code retval = bxattr_rtn_error;
2055
2056    xattr_value_list = New(alist(10, not_owned_by_alist));
2057
2058    if (unserialize_xattr_stream(jcr,
2059                                 content,
2060                                 content_length,
2061                                 xattr_value_list) != bxattr_rtn_ok) {
2062       goto get_out;
2063    }
2064
2065    /*
2066     * See how big the propertylist must be.
2067     */
2068    xattrbuf_size = 0;
2069    foreach_alist(current_xattr, xattr_value_list) {
2070       xattrbuf_size += sizeof_proplist_entry(current_xattr->name, current_xattr->value_length);
2071    }
2072
2073    xattrbuf = (char *)malloc(xattrbuf_size);
2074
2075    /*
2076     * Add all value pairs to the proplist.
2077     */
2078    cnt = 0;
2079    bp = xattrbuf;
2080    foreach_alist(current_xattr, xattr_value_list) {
2081       cnt = add_proplist_entry(current_xattr->name, 0, current_xattr->value_length,
2082                                current_xattr->value, &bp);
2083    }
2084
2085    /*
2086     * Sanity check.
2087     */
2088    if (cnt != xattrbuf_size) {
2089       Mmsg1(jcr->errmsg, _("Unable create proper proplist to restore xattrs on file \"%s\"\n"),
2090             jcr->last_fname);
2091       Dmsg1(100, "%s", jcr->errmsg);
2092       goto get_out;
2093    }
2094
2095    /*
2096     * Restore the list of extended attributes on the file.
2097     */
2098    cnt = setproplist(jcr->last_fname, 1, xattrbuf_size, xattrbuf);
2099    switch (cnt) {
2100    case -1: {
2101       berrno be;
2102
2103       switch (errno) {
2104       case EOPNOTSUPP:
2105          /*
2106           * If the filesystem reports it doesn't support XATTRs we clear
2107           * the BXATTR_FLAG_RESTORE_NATIVE flag so we skip XATTR restores
2108           * on all other files on the same filesystem. The
2109           * BXATTR_FLAG_RESTORE_NATIVE flags gets sets again when we
2110           * change from one filesystem to an other.
2111           */
2112          jcr->xattr_ctx->flags &= ~BXATTR_FLAG_RESTORE_NATIVE;
2113          retval = bxattr_rtn_ok;
2114          goto get_out;
2115       default:
2116          Mmsg2(jcr->errmsg, _("setproplist error on file \"%s\": ERR=%s\n"),
2117                jcr->last_fname, be.bstrerror());
2118          Dmsg1(100, "%s", jcr->errmsg);
2119          goto get_out;
2120       }
2121       break;
2122    }
2123    default:
2124       break;
2125    }
2126
2127    retval = bxattr_rtn_ok;
2128
2129 get_out:
2130    if (xattrbuf) {
2131       free(xattrbuf);
2132    }
2133    xattr_drop_internal_table(xattr_value_list);
2134
2135    return retval;
2136 }
2137
2138 /*
2139  * Function pointers to the build and restore function to use for these xattrs.
2140  */
2141 static bxattr_rtn_code (*os_backup_xattr_streams)
2142                         (JCR *jcr, FF_PKT *ff_pkt) =
2143                         tru64_backup_xattr_streams;
2144 static bxattr_rtn_code (*os_restore_xattr_streams)
2145                         (JCR *jcr, int stream, char *content, uint32_t content_length) =
2146                         tru64_restore_xattr_streams;
2147
2148 #elif defined(HAVE_SUN_OS)
2149 /*
2150  * Solaris extended attributes were introduced in Solaris 9
2151  * by PSARC 1999/209
2152  *
2153  * Solaris extensible attributes were introduced in OpenSolaris
2154  * by PSARC 2007/315 Solaris extensible attributes are also
2155  * sometimes called extended system attributes.
2156  *
2157  * man fsattr(5) on Solaris gives a wealth of info. The most
2158  * important bits are:
2159  *
2160  * Attributes are logically supported as files within the  file
2161  * system.   The  file  system  is  therefore augmented with an
2162  * orthogonal name space of file attributes. Any file  (includ-
2163  * ing  attribute files) can have an arbitrarily deep attribute
2164  * tree associated with it. Attribute values  are  accessed  by
2165  * file descriptors obtained through a special attribute inter-
2166  * face.  This logical view of "attributes as files" allows the
2167  * leveraging  of  existing file system interface functionality
2168  * to support the construction, deletion, and  manipulation  of
2169  * attributes.
2170  *
2171  * The special files  "."  and  ".."  retain  their  accustomed
2172  * semantics within the attribute hierarchy.  The "." attribute
2173  * file refers to the current directory and the ".."  attribute
2174  * file  refers to the parent directory.  The unnamed directory
2175  * at the head of each attribute tree is considered the "child"
2176  * of  the  file it is associated with and the ".." file refers
2177  * to the associated file.  For  any  non-directory  file  with
2178  * attributes,  the  ".." entry in the unnamed directory refers
2179  * to a file that is not a directory.
2180  *
2181  * Conceptually, the attribute model is fully general. Extended
2182  * attributes  can  be  any  type of file (doors, links, direc-
2183  * tories, and so forth) and can even have their own attributes
2184  * (fully  recursive).   As a result, the attributes associated
2185  * with a file could be an arbitrarily deep directory hierarchy
2186  * where each attribute could have an equally complex attribute
2187  * tree associated with it.  Not all implementations  are  able
2188  * to,  or  want to, support the full model. Implementation are
2189  * therefore permitted to reject operations that are  not  sup-
2190  * ported.   For  example,  the implementation for the UFS file
2191  * system allows only regular files as attributes (for example,
2192  * no sub-directories) and rejects attempts to place attributes
2193  * on attributes.
2194  *
2195  * The following list details the operations that are  rejected
2196  * in the current implementation:
2197  *
2198  * link                     Any attempt to create links between
2199  *                          attribute  and  non-attribute space
2200  *                          is rejected  to  prevent  security-
2201  *                          related   or   otherwise  sensitive
2202  *                          attributes from being exposed,  and
2203  *                          therefore  manipulable,  as regular
2204  *                          files.
2205  *
2206  * rename                   Any  attempt  to   rename   between
2207  *                          attribute  and  non-attribute space
2208  *                          is rejected to prevent  an  already
2209  *                          linked  file from being renamed and
2210  *                          thereby circumventing the link res-
2211  *                          triction above.
2212  *
2213  * mkdir, symlink, mknod    Any  attempt  to  create  a   "non-
2214  *                          regular" file in attribute space is
2215  *                          rejected to reduce the  functional-
2216  *                          ity,  and  therefore  exposure  and
2217  *                          risk, of  the  initial  implementa-
2218  *                          tion.
2219  *
2220  * The entire available name space has been allocated to  "gen-
2221  * eral use" to bring the implementation in line with the NFSv4
2222  * draft standard [NFSv4]. That standard defines "named  attri-
2223  * butes"  (equivalent  to Solaris Extended Attributes) with no
2224  * naming restrictions.  All Sun  applications  making  use  of
2225  * opaque extended attributes will use the prefix "SUNW".
2226  *
2227  */
2228 #ifdef HAVE_SYS_ATTR_H
2229 #include <sys/attr.h>
2230 #endif
2231
2232 #ifdef HAVE_ATTR_H
2233 #include <attr.h>
2234 #endif
2235
2236 #ifdef HAVE_SYS_NVPAIR_H
2237 #include <sys/nvpair.h>
2238 #endif
2239
2240 #ifdef HAVE_SYS_ACL_H
2241 #include <sys/acl.h>
2242 #endif
2243
2244 #if !defined(HAVE_OPENAT) || \
2245     !defined(HAVE_UNLINKAT) || \
2246     !defined(HAVE_FCHOWNAT) || \
2247     !defined(HAVE_FUTIMESAT)
2248 #error "Unable to compile code because of missing openat, unlinkat, fchownat or futimesat function"
2249 #endif
2250
2251 /*
2252  * Define the supported XATTR streams for this OS
2253  */
2254 #if defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED)
2255 static int os_default_xattr_streams[2] = {
2256    STREAM_XATTR_SOLARIS,
2257    STREAM_XATTR_SOLARIS_SYS
2258 };
2259 #else
2260 static int os_default_xattr_streams[1] = {
2261    STREAM_XATTR_SOLARIS
2262 };
2263 #endif /* defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED) */
2264
2265 /*
2266  * This code creates a temporary cache with entries for each xattr which has
2267  * a link count > 1 (which indicates it has one or more hard linked counterpart(s))
2268  */
2269 static inline xattr_link_cache_entry_t *find_xattr_link_cache_entry(JCR *jcr, ino_t inum)
2270 {
2271    xattr_link_cache_entry_t *ptr;
2272
2273    foreach_alist(ptr, jcr->xattr_ctx->link_cache) {
2274       if (ptr && ptr->inum == inum) {
2275          return ptr;
2276       }
2277    }
2278    return NULL;
2279 }
2280
2281 static inline void add_xattr_link_cache_entry(JCR *jcr, ino_t inum, char *target)
2282 {
2283    xattr_link_cache_entry_t *ptr;
2284
2285    ptr = (xattr_link_cache_entry_t *)malloc(sizeof(xattr_link_cache_entry_t));
2286    memset(ptr, 0, sizeof(xattr_link_cache_entry_t));
2287    ptr->inum = inum;
2288    ptr->target = bstrdup(target);
2289
2290    if (!jcr->xattr_ctx->link_cache) {
2291       jcr->xattr_ctx->link_cache = New(alist(10, not_owned_by_alist));
2292    }
2293    jcr->xattr_ctx->link_cache->append(ptr);
2294 }
2295
2296 static inline void drop_xattr_link_cache(JCR *jcr)
2297 {
2298    xattr_link_cache_entry_t *ptr;
2299
2300    /*
2301     * Walk the list of xattr link cache entries and free allocated memory on traversing.
2302     */
2303    foreach_alist(ptr, jcr->xattr_ctx->link_cache) {
2304       free(ptr->target);
2305       free(ptr);
2306    }
2307
2308    delete jcr->xattr_ctx->link_cache;
2309    jcr->xattr_ctx->link_cache = NULL;
2310 }
2311
2312 #if defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED)
2313 /*
2314  * This function returns true if a non default extended system attribute
2315  * list is associated with fd and returns false when an error has occured
2316  * or when only extended system attributes other than archive,
2317  * av_modified or crtime are set.
2318  *
2319  * The function returns true for the following cases:
2320  *
2321  * - any extended system attribute other than the default attributes
2322  *   ('archive', 'av_modified' and 'crtime') is set
2323  * - nvlist has NULL name string
2324  * - nvpair has data type of 'nvlist'
2325  * - default data type.
2326  */
2327 static bool solaris_has_non_transient_extensible_attributes(int fd)
2328 {
2329    boolean_t value;
2330    data_type_t type;
2331    nvlist_t *response;
2332    nvpair_t *pair;
2333    f_attr_t fattr;
2334    char *name;
2335    bool retval = false;
2336
2337    if (fgetattr(fd, XATTR_VIEW_READWRITE, &response) != 0) {
2338       return false;
2339    }
2340
2341    pair = NULL;
2342    while ((pair = nvlist_next_nvpair(response, pair)) != NULL) {
2343       name = nvpair_name(pair);
2344
2345       if (name != NULL) {
2346          fattr = name_to_attr(name);
2347       } else {
2348          retval = true;
2349          goto get_out;
2350       }
2351
2352       type = nvpair_type(pair);
2353       switch (type) {
2354       case DATA_TYPE_BOOLEAN_VALUE:
2355          if (nvpair_value_boolean_value(pair, &value) != 0) {
2356             continue;
2357          }
2358          if (value && fattr != F_ARCHIVE &&
2359                       fattr != F_AV_MODIFIED) {
2360             retval = true;
2361             goto get_out;
2362          }
2363          break;
2364       case DATA_TYPE_UINT64_ARRAY:
2365          if (fattr != F_CRTIME) {
2366             retval = true;
2367             goto get_out;
2368          }
2369          break;
2370       case DATA_TYPE_NVLIST:
2371       default:
2372          retval = true;
2373          goto get_out;
2374       }
2375    }
2376
2377 get_out:
2378    if (response != NULL) {
2379       nvlist_free(response);
2380    }
2381    return retval;
2382 }
2383 #endif /* HAVE_SYS_NVPAIR_H && _PC_SATTR_ENABLED */
2384
2385 #if defined(HAVE_ACL) && !defined(HAVE_EXTENDED_ACL)
2386 /*
2387  * See if an acl is a trivial one (e.g. just the stat bits encoded as acl.)
2388  * There is no need to store those acls as we already store the stat bits too.
2389  */
2390 static bool acl_is_trivial(int count, aclent_t *entries)
2391 {
2392    int n;
2393    aclent_t *ace;
2394
2395    for (n = 0; n < count; n++) {
2396       ace = &entries[n];
2397       if (!(ace->a_type == USER_OBJ ||
2398             ace->a_type == GROUP_OBJ ||
2399             ace->a_type == OTHER_OBJ ||
2400             ace->a_type == CLASS_OBJ))
2401         return false;
2402    }
2403    return true;
2404 }
2405 #endif /* HAVE_ACL && !HAVE_EXTENDED_ACL */
2406
2407 static bxattr_rtn_code solaris_save_xattr_acl(JCR *jcr, int fd, const char *attrname, char **acl_text)
2408 {
2409    bxattr_rtn_code retval = bxattr_rtn_error;
2410 #ifdef HAVE_ACL
2411 #ifdef HAVE_EXTENDED_ACL
2412    int flags;
2413    acl_t *aclp = NULL;
2414
2415    /*
2416     * See if this attribute has an ACL
2417     */
2418    if ((fd != -1 && fpathconf(fd, _PC_ACL_ENABLED) > 0) ||
2419        pathconf(attrname, _PC_ACL_ENABLED) > 0) {
2420       /*
2421        * See if there is a non trivial acl on the file.
2422        */
2423       if ((fd != -1 && facl_get(fd, ACL_NO_TRIVIAL, &aclp) != 0) ||
2424            acl_get(attrname, ACL_NO_TRIVIAL, &aclp) != 0) {
2425          berrno be;
2426
2427          switch (errno) {
2428          case ENOENT:
2429             retval = bxattr_rtn_ok;
2430             goto get_out;
2431          default:
2432             Mmsg3(jcr->errmsg, _("Unable to get acl on xattr %s on file \"%s\": ERR=%s\n"),
2433                   attrname, jcr->last_fname, be.bstrerror());
2434             Dmsg1(100, "%s", jcr->errmsg);
2435             goto get_out;
2436          }
2437       }
2438
2439       if (aclp != NULL) {
2440 #if defined(ACL_SID_FMT)
2441          /*
2442           * New format flag added in newer Solaris versions.
2443           */
2444          flags = ACL_APPEND_ID | ACL_COMPACT_FMT | ACL_SID_FMT;
2445 #else
2446          flags = ACL_APPEND_ID | ACL_COMPACT_FMT;
2447 #endif /* ACL_SID_FMT */
2448
2449          *acl_text = acl_totext(aclp, flags);
2450          acl_free(aclp);
2451       } else {
2452          *acl_text = NULL;
2453       }
2454    } else {
2455       *acl_text = NULL;
2456    }
2457    retval = bxattr_rtn_ok;
2458 #else /* HAVE_EXTENDED_ACL */
2459    int n;
2460    aclent_t *acls = NULL;
2461
2462    /*
2463     * See if this attribute has an ACL
2464     */
2465    if (fd != -1) {
2466       n = facl(fd, GETACLCNT, 0, NULL);
2467    } else {
2468       n = acl(attrname, GETACLCNT, 0, NULL);
2469    }
2470
2471    if (n >= MIN_ACL_ENTRIES) {
2472       acls = (aclent_t *)malloc(n * sizeof(aclent_t));
2473       if ((fd != -1 && facl(fd, GETACL, n, acls) != n) ||
2474           acl(attrname, GETACL, n, acls) != n) {
2475          berrno be;
2476
2477          switch (errno) {
2478          case ENOENT:
2479             free(acls);
2480             retval = bxattr_rtn_ok;
2481             goto get_out;
2482          default:
2483             Mmsg3(jcr->errmsg, _("Unable to get acl on xattr %s on file \"%s\": ERR=%s\n"),
2484                   attrname, jcr->last_fname, be.bstrerror());
2485             Dmsg1(100, "%s", jcr->errmsg);
2486             free(acls);
2487             goto get_out;
2488          }
2489       }
2490
2491       /*
2492        * See if there is a non trivial acl on the file.
2493        */
2494       if (!acl_is_trivial(n, acls)) {
2495          if ((*acl_text = acltotext(acls, n)) == NULL) {
2496             berrno be;
2497
2498             Mmsg3(jcr->errmsg, _("Unable to get acl text on xattr %s on file \"%s\": ERR=%s\n"),
2499                   attrname, jcr->last_fname, be.bstrerror());
2500             Dmsg1(100, "%s", jcr->errmsg);
2501             free(acls);
2502             goto get_out;
2503          }
2504       } else {
2505          *acl_text = NULL;
2506       }
2507
2508      free(acls);
2509    } else {
2510       *acl_text = NULL;
2511    }
2512    retval = bxattr_rtn_ok;
2513 #endif /* HAVE_EXTENDED_ACL */
2514
2515 #else /* HAVE_ACL */
2516    retval = bxattr_rtn_ok;
2517 #endif /* HAVE_ACL */
2518
2519 get_out:
2520    return retval;
2521 }
2522
2523 /*
2524  * Forward declaration for recursive function call.
2525  */
2526 static bxattr_rtn_code solaris_save_xattrs(JCR *jcr, const char *xattr_namespace, const char *attr_parent);
2527
2528 /*
2529  * Save an extended or extensible attribute.
2530  * This is stored as an opaque stream of bytes with the following encoding:
2531  *
2532  * <xattr_name>\0<stat_buffer>\0<acl_string>\0<actual_xattr_ctx>
2533  *
2534  * or for a hardlinked or symlinked attribute
2535  *
2536  * <xattr_name>\0<stat_buffer>\0<xattr_link_source>\0
2537  *
2538  * xattr_name can be a subpath relative to the file the xattr is on.
2539  * stat_buffer is the string representation of the stat struct.
2540  * acl_string is an acl text when a non trivial acl is set on the xattr.
2541  * actual_xattr_ctx is the content of the xattr file.
2542  */
2543 static bxattr_rtn_code solaris_save_xattr(JCR *jcr, int fd, const char *xattr_namespace,
2544                                            const char *attrname, bool toplevel_hidden_dir, int stream)
2545 {
2546    int cnt;
2547    int attrfd = -1;
2548    struct stat st;
2549    xattr_link_cache_entry_t *xlce;
2550    char target_attrname[PATH_MAX];
2551    char link_source[PATH_MAX];
2552    char *acl_text = NULL;
2553    char attribs[MAXSTRING];
2554    char buffer[XATTR_BUFSIZ];
2555    bxattr_rtn_code retval = bxattr_rtn_error;
2556
2557    bsnprintf(target_attrname, sizeof(target_attrname), "%s%s", xattr_namespace, attrname);
2558
2559    /*
2560     * Get the stats of the extended or extensible attribute.
2561     */
2562    if (fstatat(fd, attrname, &st, AT_SYMLINK_NOFOLLOW) < 0) {
2563       berrno be;
2564
2565       switch (errno) {
2566       case ENOENT:
2567          retval = bxattr_rtn_ok;
2568          goto get_out;
2569       default:
2570          Mmsg3(jcr->errmsg, _("Unable to get status on xattr %s on file \"%s\": ERR=%s\n"),
2571                target_attrname, jcr->last_fname, be.bstrerror());
2572          Dmsg1(100, "%s", jcr->errmsg);
2573          goto get_out;
2574       }
2575    }
2576
2577    /*
2578     * Based on the filetype perform the correct action. We support most filetypes here, more
2579     * then the actual implementation on Solaris supports so some code may never get executed
2580     * due to limitations in the implementation.
2581     */
2582    switch (st.st_mode & S_IFMT) {
2583    case S_IFIFO:
2584    case S_IFCHR:
2585    case S_IFBLK:
2586       /*
2587        * Get any acl on the xattr.
2588        */
2589       if (solaris_save_xattr_acl(jcr, attrfd, attrname, &acl_text) != bxattr_rtn_ok)
2590          goto get_out;
2591
2592       /*
2593        * The current implementation of xattr on Solaris doesn't support this,
2594        * but if it ever does we are prepared.
2595        * Encode the stat struct into an ASCII representation.
2596        */
2597       encode_stat(attribs, &st, sizeof(st), 0, stream);
2598       cnt = bsnprintf(buffer, sizeof(buffer), "%s%c%s%c%s%c",
2599                       target_attrname, 0, attribs, 0,
2600                       (acl_text) ? acl_text : "", 0);
2601       break;
2602    case S_IFDIR:
2603       /*
2604        * Get any acl on the xattr.
2605        */
2606       if (solaris_save_xattr_acl(jcr, attrfd, attrname, &acl_text) != bxattr_rtn_ok)
2607          goto get_out;
2608
2609       /*
2610        * See if this is the toplevel_hidden_dir being saved.
2611        */
2612       if (toplevel_hidden_dir) {
2613          /*
2614           * Save the data for later storage when we encounter a real xattr.
2615           * We store the data in the jcr->xattr_ctx->content buffer
2616           * and flush that just before sending out the first real xattr.
2617           * Encode the stat struct into an ASCII representation and jump
2618           * out of the function.
2619           */
2620          encode_stat(attribs, &st, sizeof(st), 0, stream);
2621          cnt = bsnprintf(buffer, sizeof(buffer),
2622                          "%s%c%s%c%s%c",
2623                          target_attrname, 0, attribs, 0,
2624                          (acl_text) ? acl_text : "", 0);
2625          pm_memcpy(jcr->xattr_ctx->content, buffer, cnt);
2626          jcr->xattr_ctx->content_length = cnt;
2627          goto get_out;
2628       } else {
2629          /*
2630           * The current implementation of xattr on Solaris doesn't support this,
2631           * but if it ever does we are prepared.
2632           * Encode the stat struct into an ASCII representation.
2633           */
2634          encode_stat(attribs, &st, sizeof(st), 0, stream);
2635          cnt = bsnprintf(buffer, sizeof(buffer),
2636                          "%s%c%s%c%s%c",
2637                          target_attrname, 0, attribs, 0,
2638                          (acl_text) ? acl_text : "", 0);
2639       }
2640       break;
2641    case S_IFREG:
2642       /*
2643        * If this is a hardlinked file check the inode cache for a hit.
2644        */
2645       if (st.st_nlink > 1) {
2646          /*
2647           * See if the cache already knows this inode number.
2648           */
2649          if ((xlce = find_xattr_link_cache_entry(jcr, st.st_ino)) != NULL) {
2650             /*
2651              * Generate a xattr encoding with the reference to the target in there.
2652              */
2653             encode_stat(attribs, &st, sizeof(st), st.st_ino, stream);
2654             cnt = bsnprintf(buffer, sizeof(buffer),
2655                             "%s%c%s%c%s%c",
2656                             target_attrname, 0, attribs, 0, xlce->target, 0);
2657             pm_memcpy(jcr->xattr_ctx->content, buffer, cnt);
2658             jcr->xattr_ctx->content_length = cnt;
2659             retval = send_xattr_stream(jcr, stream);
2660
2661             /*
2662              * For a hard linked file we are ready now, no need to recursively
2663              * save the attributes.
2664              */
2665             goto get_out;
2666          }
2667
2668          /*
2669           * Store this hard linked file in the cache.
2670           * Store the name relative to the top level xattr space.
2671           */
2672          add_xattr_link_cache_entry(jcr, st.st_ino, target_attrname + 1);
2673       }
2674
2675       /*
2676        * Get any acl on the xattr.
2677        */
2678       if (solaris_save_xattr_acl(jcr, attrfd, attrname, &acl_text) != bxattr_rtn_ok) {
2679          goto get_out;
2680       }
2681
2682       /*
2683        * Encode the stat struct into an ASCII representation.
2684        */
2685       encode_stat(attribs, &st, sizeof(st), 0, stream);
2686       cnt = bsnprintf(buffer, sizeof(buffer),
2687                      "%s%c%s%c%s%c",
2688                      target_attrname, 0, attribs, 0, (acl_text) ? acl_text : "", 0);
2689
2690       /*
2691        * Open the extended or extensible attribute file.
2692        */
2693       if ((attrfd = openat(fd, attrname, O_RDONLY)) < 0) {
2694          berrno be;
2695
2696          switch (errno) {
2697          case ENOENT:
2698             retval = bxattr_rtn_ok;
2699             goto get_out;
2700          default:
2701             Mmsg3(jcr->errmsg, _("Unable to open xattr %s on \"%s\": ERR=%s\n"),
2702                   target_attrname, jcr->last_fname, be.bstrerror());
2703             Dmsg1(100, "%s", jcr->errmsg);
2704             goto get_out;
2705          }
2706       }
2707       break;
2708    case S_IFLNK:
2709       /*
2710        * The current implementation of xattr on Solaris doesn't support this, but if it
2711        * ever does we are prepared.
2712        * Encode the stat struct into an ASCII representation.
2713        */
2714       if (readlink(attrname, link_source, sizeof(link_source)) < 0) {
2715          berrno be;
2716
2717          switch (errno) {
2718          case ENOENT:
2719             retval = bxattr_rtn_ok;
2720             goto get_out;
2721          default:
2722             Mmsg3(jcr->errmsg, _("Unable to read symlin %s on \"%s\": ERR=%s\n"),
2723                   target_attrname, jcr->last_fname, be.bstrerror());
2724             Dmsg1(100, "%s", jcr->errmsg);
2725             goto get_out;
2726          }
2727       }
2728
2729       /*
2730        * Generate a xattr encoding with the reference to the target in there.
2731        */
2732       encode_stat(attribs, &st, sizeof(st), st.st_ino, stream);
2733       cnt = bsnprintf(buffer, sizeof(buffer),
2734                       "%s%c%s%c%s%c",
2735                       target_attrname, 0, attribs, 0, link_source, 0);
2736       pm_memcpy(jcr->xattr_ctx->content, buffer, cnt);
2737       jcr->xattr_ctx->content_length = cnt;
2738       retval = send_xattr_stream(jcr, stream);
2739
2740       if (retval == bxattr_rtn_ok) {
2741          jcr->xattr_ctx->nr_saved++;
2742       }
2743
2744       /*
2745        * For a soft linked file we are ready now, no need to recursively save the attributes.
2746        */
2747       goto get_out;
2748    default:
2749       goto get_out;
2750    }
2751
2752    /*
2753     * See if this is the first real xattr being saved.
2754     * If it is save the toplevel_hidden_dir attributes first.
2755     * This is easy as its stored already in the
2756     * jcr->xattr_ctx->content buffer.
2757     */
2758    if (jcr->xattr_ctx->nr_saved == 0) {
2759       retval = send_xattr_stream(jcr, STREAM_XATTR_SOLARIS);
2760       if (retval != bxattr_rtn_ok) {
2761          goto get_out;
2762       }
2763       jcr->xattr_ctx->nr_saved++;
2764    }
2765
2766    pm_memcpy(jcr->xattr_ctx->content, buffer, cnt);
2767    jcr->xattr_ctx->content_length = cnt;
2768
2769    /*
2770     * Only dump the content of regular files.
2771     */
2772    switch (st.st_mode & S_IFMT) {
2773    case S_IFREG:
2774       if (st.st_size > 0) {
2775          /*
2776           * Protect ourself against things getting out of hand.
2777           */
2778          if (st.st_size >= MAX_XATTR_LENGTH) {
2779             Mmsg2(jcr->errmsg,
2780                   _("Xattr stream on file \"%s\" exceeds maximum size of %d bytes\n"),
2781                   jcr->last_fname, MAX_XATTR_LENGTH);
2782             goto get_out;
2783          }
2784
2785          while ((cnt = read(attrfd, buffer, sizeof(buffer))) > 0) {
2786             jcr->xattr_ctx->content =
2787                check_pool_memory_size(jcr->xattr_ctx->content,
2788                   jcr->xattr_ctx->content_length + cnt);
2789             memcpy(jcr->xattr_ctx->content +
2790                    jcr->xattr_ctx->content_length, buffer, cnt);
2791             jcr->xattr_ctx->content_length += cnt;
2792          }
2793
2794          if (cnt < 0) {
2795             Mmsg2(jcr->errmsg, _("Unable to read content of xattr %s on file \"%s\"\n"),
2796                   target_attrname, jcr->last_fname);
2797             Dmsg1(100, "%s", jcr->errmsg);
2798             goto get_out;
2799          }
2800       }
2801       break;
2802
2803    default:
2804       break;
2805    }
2806
2807    /*
2808     * We build a new xattr stream send it to the SD.
2809     */
2810    retval = send_xattr_stream(jcr, stream);
2811    if (retval != bxattr_rtn_ok) {
2812        goto get_out;
2813    }
2814    jcr->xattr_ctx->nr_saved++;
2815
2816    /*
2817     * Recursivly call solaris_save_extended_attributes for archiving the attributes
2818     * available on this extended attribute.
2819     */
2820    retval = solaris_save_xattrs(jcr, xattr_namespace, attrname);
2821
2822    /*
2823     * The recursive call could change our working dir so change back to the wanted workdir.
2824     */
2825    if (fchdir(fd) < 0) {
2826       berrno be;
2827
2828       switch (errno) {
2829       case ENOENT:
2830          retval = bxattr_rtn_ok;
2831          goto get_out;
2832       default:
2833          Mmsg2(jcr->errmsg, _("Unable to chdir to xattr space of file \"%s\": ERR=%s\n"),
2834                jcr->last_fname, be.bstrerror());
2835          Dmsg1(100, "%s", jcr->errmsg);
2836          goto get_out;
2837       }
2838    }
2839
2840 get_out:
2841    if (acl_text != NULL) {
2842       free(acl_text);
2843    }
2844    if (attrfd != -1) {
2845       close(attrfd);
2846    }
2847    return retval;
2848 }
2849
2850 static bxattr_rtn_code solaris_save_xattrs(JCR *jcr, const char *xattr_namespace, const char *attr_parent)
2851 {
2852    const char *name;
2853    int fd, filefd = -1, attrdirfd = -1;
2854    DIR *dirp;
2855    struct dirent *dp;
2856    char current_xattr_namespace[PATH_MAX];
2857    bxattr_rtn_code retval = bxattr_rtn_error;
2858
2859    /*
2860     * Determine what argument to use. Use attr_parent when set
2861     * (recursive call) or jcr->last_fname for first call. Also save
2862     * the current depth of the xattr_space we are in.
2863     */
2864    if (attr_parent) {
2865       name = attr_parent;
2866       if (xattr_namespace) {
2867          bsnprintf(current_xattr_namespace, sizeof(current_xattr_namespace), "%s%s/",
2868                    xattr_namespace, attr_parent);
2869       } else {
2870          bstrncpy(current_xattr_namespace, "/", sizeof(current_xattr_namespace));
2871       }
2872    } else {
2873       name = jcr->last_fname;
2874       bstrncpy(current_xattr_namespace, "/", sizeof(current_xattr_namespace));
2875    }
2876
2877    /*
2878     * Open the file on which to save the xattrs read-only.
2879     */
2880    if ((filefd = open(name, O_RDONLY | O_NONBLOCK)) < 0) {
2881       berrno be;
2882
2883       switch (errno) {
2884       case ENOENT:
2885          retval = bxattr_rtn_ok;
2886          goto get_out;
2887       default:
2888          Mmsg2(jcr->errmsg, _("Unable to open file \"%s\": ERR=%s\n"),
2889                jcr->last_fname, be.bstrerror());
2890          Dmsg1(100, "%s", jcr->errmsg);
2891          goto get_out;
2892       }
2893    }
2894
2895    /*
2896     * Open the xattr naming space.
2897     */
2898    if ((attrdirfd = openat(filefd, ".", O_RDONLY | O_XATTR)) < 0) {
2899       berrno be;
2900
2901       switch (errno) {
2902       case EINVAL:
2903          /*
2904           * Gentile way of the system saying this type of xattr layering is not supported.
2905           * Which is not problem we just forget about this this xattr.
2906           * But as this is not an error we return a positive return value.
2907           */
2908          retval = bxattr_rtn_ok;
2909          goto get_out;
2910       case ENOENT:
2911          retval = bxattr_rtn_ok;
2912          goto get_out;
2913       default:
2914          Mmsg3(jcr->errmsg, _("Unable to open xattr space %s on file \"%s\": ERR=%s\n"),
2915                name, jcr->last_fname, be.bstrerror());
2916          Dmsg1(100, "%s", jcr->errmsg);
2917          goto get_out;
2918       }
2919    }
2920
2921   /*
2922    * We need to change into the attribute directory to determine if each of the
2923    * attributes should be saved.
2924    */
2925    if (fchdir(attrdirfd) < 0) {
2926       berrno be;
2927
2928       Mmsg2(jcr->errmsg, _("Unable to chdir to xattr space on file \"%s\": ERR=%s\n"),
2929             jcr->last_fname, be.bstrerror());
2930       Dmsg1(100, "%s", jcr->errmsg);
2931       goto get_out;
2932    }
2933
2934    /*
2935     * Save the data of the toplevel xattr hidden_dir. We save this one before anything
2936     * else because the readdir returns "." entry after the extensible attr entry.
2937     * And as we want this entry before anything else we better just save its data.
2938     */
2939    if (!attr_parent)
2940       solaris_save_xattr(jcr, attrdirfd, current_xattr_namespace, ".",
2941                          true, STREAM_XATTR_SOLARIS);
2942
2943    if ((fd = dup(attrdirfd)) == -1 ||
2944        (dirp = fdopendir(fd)) == (DIR *)NULL) {
2945       berrno be;
2946
2947       Mmsg2(jcr->errmsg, _("Unable to list the xattr space on file \"%s\": ERR=%s\n"),
2948             jcr->last_fname, be.bstrerror());
2949       Dmsg1(100, "%s", jcr->errmsg);
2950
2951       goto get_out;
2952    }
2953
2954    /*
2955     * Walk the namespace.
2956     */
2957    while ((dp = readdir(dirp)) != NULL) {
2958       /*
2959        * Skip only the toplevel . dir.
2960        */
2961       if (!attr_parent && bstrcmp(dp->d_name, "."))
2962          continue;
2963
2964       /*
2965        * Skip all .. directories
2966        */
2967       if (bstrcmp(dp->d_name, ".."))
2968          continue;
2969
2970       Dmsg3(400, "processing extended attribute %s%s on file \"%s\"\n",
2971          current_xattr_namespace, dp->d_name, jcr->last_fname);
2972
2973 #if defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED)
2974       /*
2975        * We are not interested in read-only extensible attributes.
2976        */
2977       if (bstrcmp(dp->d_name, VIEW_READONLY)) {
2978          Dmsg3(400, "Skipping readonly extensible attributes %s%s on file \"%s\"\n",
2979             current_xattr_namespace, dp->d_name, jcr->last_fname);
2980
2981          continue;
2982       }
2983
2984       /*
2985        * We are only interested in read-write extensible attributes
2986        * when they contain non-transient values.
2987        */
2988       if (bstrcmp(dp->d_name, VIEW_READWRITE)) {
2989          /*
2990           * Determine if there are non-transient system attributes at the toplevel.
2991           * We need to provide a fd to the open file.
2992           */
2993          if (!solaris_has_non_transient_extensible_attributes(filefd)) {
2994             Dmsg3(400, "Skipping transient extensible attributes %s%s on file \"%s\"\n",
2995                current_xattr_namespace, dp->d_name, jcr->last_fname);
2996             continue;
2997          }
2998
2999          /*
3000           * Save the xattr.
3001           */
3002          solaris_save_xattr(jcr, attrdirfd, current_xattr_namespace, dp->d_name,
3003                             false, STREAM_XATTR_SOLARIS_SYS);
3004          continue;
3005       }
3006 #endif /* HAVE_SYS_NVPAIR_H && _PC_SATTR_ENABLED */
3007
3008       /*
3009        * Save the xattr.
3010        */
3011       solaris_save_xattr(jcr, attrdirfd, current_xattr_namespace, dp->d_name,
3012                          false, STREAM_XATTR_SOLARIS);
3013    }
3014
3015    closedir(dirp);
3016    retval = bxattr_rtn_ok;
3017
3018 get_out:
3019    if (attrdirfd != -1)
3020       close(attrdirfd);
3021    if (filefd != -1)
3022       close(filefd);
3023    return retval;
3024 }
3025
3026 #ifdef HAVE_ACL
3027 static bxattr_rtn_code solaris_restore_xattr_acl(JCR *jcr,
3028                                                   int fd,
3029                                                   const char *attrname,
3030                                                   char *acl_text)
3031 {
3032 #ifdef HAVE_EXTENDED_ACL
3033    int error;
3034    acl_t *aclp = NULL;
3035
3036    if ((error = acl_fromtext(acl_text, &aclp)) != 0) {
3037       Mmsg1(jcr->errmsg,
3038             _("Unable to convert acl from text on file \"%s\"\n"),
3039             jcr->last_fname);
3040       return bxattr_rtn_error;
3041    }
3042
3043    if ((fd != -1 && facl_set(fd, aclp) != 0) ||
3044         acl_set(attrname, aclp) != 0) {
3045       berrno be;
3046
3047       Mmsg3(jcr->errmsg, _("Unable to restore acl of xattr %s on file \"%s\": ERR=%s\n"),
3048             attrname, jcr->last_fname, be.bstrerror());
3049       Dmsg1(100, "%s", jcr->errmsg);
3050       return bxattr_rtn_error;
3051    }
3052
3053    if (aclp) {
3054       acl_free(aclp);
3055    }
3056    return bxattr_rtn_ok;
3057
3058 #else /* HAVE_EXTENDED_ACL */
3059    int n;
3060    aclent_t *acls = NULL;
3061
3062    acls = aclfromtext(acl_text, &n);
3063    if (!acls) {
3064       if ((fd != -1 && facl(fd, SETACL, n, acls) != 0) ||
3065            acl(attrname, SETACL, n, acls) != 0) {
3066          berrno be;
3067
3068          Mmsg3(jcr->errmsg, _("Unable to restore acl of xattr %s on file \"%s\": ERR=%s\n"),
3069                attrname, jcr->last_fname, be.bstrerror());
3070          Dmsg1(100, "%s", jcr->errmsg);
3071          return bxattr_rtn_error;
3072       }
3073    }
3074
3075    if (acls) {
3076       free(acls);
3077    }
3078    return bxattr_rtn_ok;
3079
3080 #endif /* HAVE_EXTENDED_ACL */
3081
3082 }
3083 #endif /* HAVE_ACL */
3084
3085 static bxattr_rtn_code solaris_restore_xattrs(JCR *jcr,
3086                                                bool is_extensible,
3087                                                char *content,
3088                                                uint32_t content_length)
3089
3090 {
3091    int fd, filefd = -1, attrdirfd = -1, attrfd = -1;
3092    int used_bytes, cnt;
3093    char *bp, *target_attrname, *attribs;
3094    char *linked_target = NULL;
3095    char *acl_text = NULL;
3096    char *data = NULL;
3097    int32_t inum;
3098    struct stat st;
3099    struct timeval times[2];
3100    bxattr_rtn_code retval = bxattr_rtn_error;
3101
3102    /*
3103     * Restore the xattr stream. First the part that is the same for all xattrs.
3104     */
3105    used_bytes = 0;
3106
3107    /*
3108     * The name of the target xattr has a leading / we are not interested
3109     * in that so skip it when decoding the string. We always start a the /
3110     * of the xattr space anyway.
3111     */
3112    target_attrname = content + 1;
3113    if ((bp = strchr(target_attrname, '\0')) == (char *)NULL ||
3114        (used_bytes = (bp - content)) >= (int32_t)(content_length - 1)) {
3115       goto restore_error;
3116    }
3117    attribs = ++bp;
3118
3119    /*
3120     * Open the file on which to restore the xattrs read-only.
3121     */
3122    if ((filefd = open(jcr->last_fname, O_RDONLY | O_NONBLOCK)) < 0) {
3123       berrno be;
3124
3125       Mmsg2(jcr->errmsg, _("Unable to open file \"%s\": ERR=%s\n"),
3126             jcr->last_fname, be.bstrerror());
3127       Dmsg1(100, "%s", jcr->errmsg);
3128       goto get_out;
3129    }
3130
3131    /*
3132     * Open the xattr naming space and make it the current working dir.
3133     */
3134    if ((attrdirfd = openat(filefd, ".", O_RDONLY | O_XATTR)) < 0) {
3135       berrno be;
3136
3137       Mmsg2(jcr->errmsg, _("Unable to open xattr space on file \"%s\": ERR=%s\n"),
3138             jcr->last_fname, be.bstrerror());
3139       Dmsg1(100, "%s", jcr->errmsg);
3140       goto get_out;
3141    }
3142
3143    if (fchdir(attrdirfd) < 0) {
3144       berrno be;
3145
3146       Mmsg2(jcr->errmsg, _("Unable to chdir to xattr space on file \"%s\": ERR=%s\n"),
3147             jcr->last_fname, be.bstrerror());
3148       Dmsg1(100, "%s", jcr->errmsg);
3149       goto get_out;
3150    }
3151
3152    /*
3153     * Try to open the correct xattr subdir based on the target_attrname given.
3154     * e.g. check if its a subdir attrname. Each / in the string makes us go
3155     * one level deeper.
3156     */
3157    while ((bp = strchr(target_attrname, '/')) != (char *)NULL) {
3158       *bp = '\0';
3159
3160       if ((fd = open(target_attrname, O_RDONLY | O_NONBLOCK)) < 0) {
3161          berrno be;
3162
3163          Mmsg3(jcr->errmsg, _("Unable to open xattr %s on file \"%s\": ERR=%s\n"),
3164                target_attrname, jcr->last_fname, be.bstrerror());
3165          Dmsg1(100, "%s", jcr->errmsg);
3166          goto get_out;
3167       }
3168
3169       close(filefd);
3170       filefd = fd;
3171
3172       /*
3173        * Open the xattr naming space.
3174        */
3175       if ((fd = openat(filefd, ".", O_RDONLY | O_XATTR)) < 0) {
3176          berrno be;
3177
3178          Mmsg3(jcr->errmsg, _("Unable to open xattr space %s on file \"%s\": ERR=%s\n"),
3179                target_attrname, jcr->last_fname, be.bstrerror());
3180          Dmsg1(100, "%s", jcr->errmsg);
3181          goto get_out;
3182       }
3183
3184       close(attrdirfd);
3185       attrdirfd = fd;
3186
3187       /*
3188        * Make the xattr space our current workingdir.
3189        */
3190       if (fchdir(attrdirfd) < 0) {
3191          berrno be;
3192
3193          Mmsg3(jcr->errmsg, _("Unable to chdir to xattr space %s on file \"%s\": ERR=%s\n"),
3194                target_attrname, jcr->last_fname, be.bstrerror());
3195          Dmsg1(100, "%s", jcr->errmsg);
3196          goto get_out;
3197       }
3198
3199       target_attrname = ++bp;
3200    }
3201
3202    /*
3203     * Decode the attributes from the stream.
3204     */
3205    decode_stat(attribs, &st, sizeof(st), &inum);
3206
3207    /*
3208     * Decode the next field (acl_text).
3209     */
3210    if ((bp = strchr(attribs, '\0')) == (char *)NULL ||
3211        (used_bytes = (bp - content)) >= (int32_t)(content_length - 1)) {
3212       goto restore_error;
3213    }
3214    acl_text = ++bp;
3215
3216    /*
3217     * Based on the filetype perform the correct action. We support most filetypes here, more
3218     * then the actual implementation on Solaris supports so some code may never get executed
3219     * due to limitations in the implementation.
3220     */
3221    switch (st.st_mode & S_IFMT) {
3222    case S_IFIFO:
3223       /*
3224        * The current implementation of xattr on Solaris doesn't support this,
3225        * but if it ever does we are prepared.
3226        */
3227       unlinkat(attrdirfd, target_attrname, 0);
3228       if (mkfifo(target_attrname, st.st_mode) < 0) {
3229          berrno be;
3230
3231          Mmsg3(jcr->errmsg, _("Unable to mkfifo xattr %s on file \"%s\": ERR=%s\n"),
3232                target_attrname, jcr->last_fname, be.bstrerror());
3233          Dmsg1(100, "%s", jcr->errmsg);
3234          goto get_out;
3235       }
3236       break;
3237    case S_IFCHR:
3238    case S_IFBLK:
3239       /*
3240        * The current implementation of xattr on Solaris doesn't support this,
3241        * but if it ever does we are prepared.
3242        */
3243       unlinkat(attrdirfd, target_attrname, 0);
3244       if (mknod(target_attrname, st.st_mode, st.st_rdev) < 0) {
3245          berrno be;
3246
3247          Mmsg3(jcr->errmsg, _("Unable to mknod xattr %s on file \"%s\": ERR=%s\n"),
3248                target_attrname, jcr->last_fname, be.bstrerror());
3249          Dmsg1(100, "%s", jcr->errmsg);
3250          goto get_out;
3251       }
3252       break;
3253    case S_IFDIR:
3254       /*
3255        * If its not the hidden_dir create the entry.
3256        * The current implementation of xattr on Solaris doesn't support this,
3257        * but if it ever does we are prepared.
3258        */
3259       if (!bstrcmp(target_attrname, ".")) {
3260          unlinkat(attrdirfd, target_attrname, AT_REMOVEDIR);
3261          if (mkdir(target_attrname, st.st_mode) < 0) {
3262             berrno be;
3263
3264             /* *** FIXME *** why not Mmsg? */
3265             Jmsg3(jcr, M_WARNING, 0, _("Unable to mkdir xattr %s on file \"%s\": ERR=%s\n"),
3266                target_attrname, jcr->last_fname, be.bstrerror());
3267             Dmsg3(100, "Unable to mkdir xattr %s on file \"%s\": ERR=%s\n",
3268                target_attrname,  jcr->last_fname, be.bstrerror());
3269             goto get_out;
3270          }
3271       }
3272       break;
3273    case S_IFREG:
3274       /*
3275        * See if this is a hard linked file. e.g. inum != 0
3276        */
3277       if (inum != 0) {
3278          linked_target = bp;
3279
3280          unlinkat(attrdirfd, target_attrname, 0);
3281          if (link(linked_target, target_attrname) < 0) {
3282             berrno be;
3283
3284             Mmsg4(jcr->errmsg, _("Unable to link xattr %s to %s on file \"%s\": ERR=%s\n"),
3285                   target_attrname, linked_target, jcr->last_fname, be.bstrerror());
3286             Dmsg1(100, "%s", jcr->errmsg);
3287             goto get_out;
3288          }
3289
3290          /*
3291           * Successfully restored xattr.
3292           */
3293          retval = bxattr_rtn_ok;
3294          goto get_out;
3295       } else {
3296          if ((bp = strchr(acl_text, '\0')) == (char *)NULL ||
3297              (used_bytes = (bp - content)) >= (int32_t)content_length) {
3298             goto restore_error;
3299          }
3300
3301          if (used_bytes < (int32_t)(content_length - 1))
3302             data = ++bp;
3303
3304          /*
3305           * Restore the actual xattr.
3306           */
3307          if (!is_extensible) {
3308             unlinkat(attrdirfd, target_attrname, 0);
3309          }
3310
3311          if ((attrfd = openat(attrdirfd, target_attrname, O_RDWR | O_CREAT | O_TRUNC, st.st_mode)) < 0) {
3312             berrno be;
3313
3314             Mmsg3(jcr->errmsg, _("Unable to open xattr %s on file \"%s\": ERR=%s\n"),
3315                   target_attrname, jcr->last_fname, be.bstrerror());
3316             Dmsg1(100, "%s", jcr->errmsg);
3317             goto get_out;
3318          }
3319       }
3320
3321       /*
3322        * Restore the actual data.
3323        */
3324       if (st.st_size > 0) {
3325          used_bytes = (data - content);
3326          cnt = content_length - used_bytes;
3327
3328          /*
3329           * Do a sanity check, the st.st_size should be the same as the number of bytes
3330           * we have available as data of the stream.
3331           */
3332          if (cnt != st.st_size) {
3333             Mmsg2(jcr->errmsg, _("Unable to restore data of xattr %s on file \"%s\": Not all data available in xattr stream\n"),
3334                   target_attrname, jcr->last_fname);
3335             Dmsg1(100, "%s", jcr->errmsg);
3336             goto get_out;
3337          }
3338
3339          while (cnt > 0) {
3340             cnt = write(attrfd, data, cnt);
3341             if (cnt < 0) {
3342                berrno be;
3343
3344                Mmsg3(jcr->errmsg, _("Unable to restore data of xattr %s on file \"%s\": ERR=%s\n"),
3345                      target_attrname, jcr->last_fname, be.bstrerror());
3346                Dmsg1(100, "%s", jcr->errmsg);
3347                goto get_out;
3348             }
3349
3350             used_bytes += cnt;
3351             data += cnt;
3352             cnt = content_length - used_bytes;
3353          }
3354       }
3355       break;
3356    case S_IFLNK:
3357       /*
3358        * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
3359        */
3360       linked_target = bp;
3361
3362       if (symlink(linked_target, target_attrname) < 0) {
3363          berrno be;
3364
3365          Mmsg4(jcr->errmsg, _("Unable to symlink xattr %s to %s on file \"%s\": ERR=%s\n"),
3366                target_attrname, linked_target, jcr->last_fname, be.bstrerror());
3367          Dmsg1(100, "%s", jcr->errmsg);
3368          goto get_out;
3369       }
3370
3371       /*
3372        * Successfully restored xattr.
3373        */
3374       retval = bxattr_rtn_ok;
3375       goto get_out;
3376    default:
3377       goto get_out;
3378    }
3379
3380    /*
3381     * Restore owner and acl for non extensible attributes.
3382     */
3383    if (!is_extensible) {
3384       if (fchownat(attrdirfd, target_attrname, st.st_uid, st.st_gid, AT_SYMLINK_NOFOLLOW) < 0) {
3385          berrno be;
3386          /* EINVAL means is not supported, no fail */
3387          if (errno == EINVAL || errno == ENOENT) {
3388             retval = bxattr_rtn_ok;
3389          } else {
3390             Mmsg3(jcr->errmsg, _("Unable to restore owner of xattr %s on file \"%s\": ERR=%s\n"),
3391                   target_attrname, jcr->last_fname, be.bstrerror());
3392             Dmsg1(100, "%s", jcr->errmsg);
3393          }
3394          goto get_out;
3395       }
3396    }
3397
3398 #ifdef HAVE_ACL
3399    if (acl_text && *acl_text)
3400       if (solaris_restore_xattr_acl(jcr, attrfd, target_attrname, acl_text) != bxattr_rtn_ok)
3401          goto get_out;
3402 #endif /* HAVE_ACL */
3403
3404    /*
3405     * For a non extensible attribute restore access and modification time on the xattr.
3406     */
3407    if (!is_extensible) {
3408       times[0].tv_sec = st.st_atime;
3409       times[0].tv_usec = 0;
3410       times[1].tv_sec = st.st_mtime;
3411       times[1].tv_usec = 0;
3412
3413       if (futimesat(attrdirfd, target_attrname, times) < 0) {
3414          berrno be;
3415          Mmsg3(jcr->errmsg, _("Unable to restore filetimes of xattr %s on file \"%s\": ERR=%s\n"),
3416                target_attrname, jcr->last_fname, be.bstrerror());
3417          Dmsg1(100, "%s", jcr->errmsg);
3418          goto get_out;
3419       }
3420    }
3421
3422    /*
3423     * Successfully restored xattr.
3424     */
3425    retval = bxattr_rtn_ok;
3426    goto get_out;
3427
3428 restore_error:
3429    Mmsg1(jcr->errmsg, _("Invalid xattr stream, failed to restore xattr stream on file \"%s\"\n"),
3430          jcr->last_fname);
3431    Dmsg1(100, "%s", jcr->errmsg);
3432
3433 get_out:
3434    if (attrfd != -1) {
3435       close(attrfd);
3436    }
3437    if (attrdirfd != -1) {
3438       close(attrdirfd);
3439    }
3440    if (filefd != -1) {
3441       close(filefd);
3442    }
3443    return retval;
3444 }
3445
3446 static bxattr_rtn_code solaris_backup_xattr_streams(JCR *jcr, FF_PKT *ff_pkt)
3447 {
3448    char cwd[PATH_MAX];
3449    bxattr_rtn_code retval = bxattr_rtn_ok;
3450
3451    /*
3452     * First see if extended attributes or extensible attributes are present.
3453     * If not just pretend things went ok.
3454     */
3455    if (pathconf(jcr->last_fname, _PC_XATTR_EXISTS) > 0) {
3456       jcr->xattr_ctx->nr_saved = 0;
3457
3458       /*
3459        * As we change the cwd in the save function save the current cwd
3460        * for restore after return from the solaris_save_xattrs function.
3461        */
3462       getcwd(cwd, sizeof(cwd));
3463       retval = solaris_save_xattrs(jcr, NULL, NULL);
3464       chdir(cwd);
3465       if (jcr->xattr_ctx->link_cache) {
3466          drop_xattr_link_cache(jcr);
3467       }
3468    }
3469    return retval;
3470 }
3471
3472 static bxattr_rtn_code solaris_restore_xattr_streams(JCR *jcr,
3473                                                     int stream,
3474                                                     char *content,
3475                                                     uint32_t content_length)
3476 {
3477    char cwd[PATH_MAX];
3478    bool is_extensible = false;
3479    bxattr_rtn_code retval = bxattr_rtn_error;
3480
3481    /*
3482     * First make sure we can restore xattr on the filesystem.
3483     */
3484    switch (stream) {
3485 #if defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED)
3486    case STREAM_XATTR_SOLARIS_SYS:
3487       if (pathconf(jcr->last_fname, _PC_SATTR_ENABLED) <= 0) {
3488          Mmsg1(jcr->errmsg, _("Failed to restore extensible attributes on file \"%s\"\n"),
3489                jcr->last_fname);
3490          Dmsg1(100, "%s", jcr->errmsg);
3491          goto get_out;
3492       }
3493
3494       is_extensible = true;
3495       break;
3496 #endif
3497    case STREAM_XATTR_SOLARIS:
3498       if (pathconf(jcr->last_fname, _PC_XATTR_ENABLED) <= 0) {
3499          Mmsg1(jcr->errmsg, _("Failed to restore extended attributes on file \"%s\"\n"),
3500                jcr->last_fname);
3501          Dmsg1(100, "%s", jcr->errmsg);
3502          goto get_out;
3503       }
3504       break;
3505    default:
3506       goto get_out;
3507    }
3508
3509    /*
3510     * As we change the cwd in the restore function save the current cwd
3511     * for restore after return from the solaris_restore_xattrs function.
3512     */
3513    getcwd(cwd, sizeof(cwd));
3514    retval = solaris_restore_xattrs(jcr, is_extensible, content, content_length);
3515    chdir(cwd);
3516
3517 get_out:
3518    return retval;
3519 }
3520
3521
3522 /*
3523  * Function pointers to the build and restore function to use for these xattrs.
3524  */
3525 static bxattr_rtn_code (*os_backup_xattr_streams)
3526                         (JCR *jcr, FF_PKT *ff_pkt) =
3527                         solaris_backup_xattr_streams;
3528 static bxattr_rtn_code (*os_restore_xattr_streams)
3529                         (JCR *jcr, int stream, char *content, uint32_t content_length) =
3530                         solaris_restore_xattr_streams;
3531
3532 #endif /* defined(HAVE_SUN_OS) */
3533
3534 /*
3535  * Entry points when compiled with support for XATTRs on a supported platform.
3536  */
3537 bool backup_xattr_streams(JCR *jcr, FF_PKT *ff_pkt)
3538 {
3539    bxattr_rtn_code rtn = bxattr_rtn_ok;
3540
3541    if (!(ff_pkt->flags & FO_XATTR && !ff_pkt->cmd_plugin)) {
3542       return true;
3543    }
3544
3545    jcr->errmsg[0] = 0;
3546
3547    /*
3548     * See if we are changing from one device to an other.
3549     * We save the current device we are scanning and compare
3550     * it with the current st_dev in the last stat performed on
3551     * the file we are currently storing.
3552     */
3553    if (jcr->xattr_ctx->current_dev != ff_pkt->statp.st_dev) {
3554       /*
3555        * Reset the acl save flags.
3556        */
3557       jcr->xattr_ctx->flags = 0;
3558       jcr->xattr_ctx->flags |= BXATTR_FLAG_SAVE_NATIVE;
3559
3560       /*
3561        * Save that we started scanning a new filesystem.
3562        */
3563       jcr->xattr_ctx->current_dev = ff_pkt->statp.st_dev;
3564    }
3565
3566    if ((jcr->xattr_ctx->flags & BXATTR_FLAG_SAVE_NATIVE) && os_restore_xattr_streams) {
3567       rtn = os_backup_xattr_streams(jcr, ff_pkt);
3568    }
3569    switch (rtn) {
3570    case bxattr_rtn_fatal:
3571       return false;
3572    case bxattr_rtn_ok:
3573       return true;
3574    case bxattr_rtn_error:
3575       if (jcr->xattr_ctx->nr_errors < XATTR_MAX_ERROR_PRINT_PER_JOB) {
3576          if (jcr->errmsg[0]) {
3577             Jmsg(jcr, M_WARNING, 0, "Operating system XATTRs not configured.\n");
3578          } else {
3579             Jmsg(jcr, M_WARNING, 0, "%s", jcr->errmsg);
3580          }
3581          jcr->xattr_ctx->nr_errors++;
3582       }
3583       return true;
3584    }
3585    /* Theoretically we cannot get here */
3586    return false;
3587
3588 }
3589
3590 bxattr_rtn_code restore_xattr_streams(JCR *jcr,
3591                                      int stream,
3592                                      char *content,
3593                                      uint32_t content_length)
3594 {
3595    int ret;
3596    struct stat st;
3597    unsigned int cnt;
3598    bxattr_rtn_code retval = bxattr_rtn_error;
3599
3600    /*
3601     * See if we are changing from one device to an other.
3602     * We save the current device we are restoring to and compare
3603     * it with the current st_dev in the last stat performed on
3604     * the file we are currently restoring.
3605     */
3606    ret = lstat(jcr->last_fname, &st);
3607    if (ret < 0) {
3608       berrno be;
3609       if (errno == ENOENT) {
3610          retval = bxattr_rtn_ok;
3611       } else {
3612          Mmsg2(jcr->errmsg, _("Unable to stat file \"%s\": ERR=%s\n"),
3613                jcr->last_fname, be.bstrerror());
3614          Dmsg1(100, "%s", jcr->errmsg);
3615       }
3616       goto get_out;
3617    }
3618    if (jcr->xattr_ctx->current_dev != st.st_dev) {
3619       /*
3620        * Reset the acl save flags.
3621        */
3622       jcr->xattr_ctx->flags = 0;
3623       jcr->xattr_ctx->flags |= BXATTR_FLAG_RESTORE_NATIVE;
3624
3625       /*
3626        * Save that we started restoring to a new filesystem.
3627        */
3628       jcr->xattr_ctx->current_dev = st.st_dev;
3629    }
3630
3631    /*
3632     * See if we are still restoring native xattr to this filesystem.
3633     */
3634    if ((jcr->xattr_ctx->flags & BXATTR_FLAG_RESTORE_NATIVE) && os_restore_xattr_streams) {
3635       /*
3636        * See if we can restore this stream, and ifso give it a try.
3637        */
3638       for (cnt = 0; cnt < sizeof(os_default_xattr_streams) / sizeof(int); cnt++) {
3639          if (os_default_xattr_streams[cnt] == stream) {
3640             retval = os_restore_xattr_streams(jcr, stream, content, content_length);
3641             goto get_out;
3642          }
3643       }
3644    } else {
3645       /*
3646        * Increment error count but don't log an error again for the same filesystem.
3647        */
3648       jcr->xattr_ctx->nr_errors++;
3649       retval = bxattr_rtn_ok;
3650       goto get_out;
3651    }
3652
3653    /*
3654     * Issue a warning and discard the message. But pretend the restore was ok.
3655     */
3656    Jmsg2(jcr, M_WARNING, 0,
3657          _("Cannot restore Extended Attributes of %s - incompatible xattr stream encountered - %d\n"),
3658          jcr->last_fname, stream);
3659
3660 get_out:
3661    return retval;
3662 }
3663 #endif