2 Bacula(R) - The Network Backup Solution
4 Copyright (C) 2000-2016 Kern Sibbald
6 The original author of Bacula is Kern Sibbald, with contributions
7 from many others, a complete list can be found in the file AUTHORS.
9 You may use this file and others of this release according to the
10 license defined in the LICENSE file, which includes the Affero General
11 Public License, v3.0 ("AGPLv3") and some additional permissions and
12 terms pursuant to its AGPLv3 Section 7.
14 This notice must be preserved when any source code is
15 conveyed and/or propagated.
17 Bacula(R) is a registered trademark of Kern Sibbald.
20 * Major refactoring of ACL and XATTR code written by:
22 * Radosław Korzeniewski, MMXVI
23 * radoslaw@korzeniewski.net, radekk@inteos.pl
24 * Inteos Sp. z o.o. http://www.inteos.pl/
30 #include "xacl_solaris.h"
32 #if defined(HAVE_SUN_OS)
34 * Define the supported ACL streams for this OS
36 static const int os_acl_streams[] = {
37 STREAM_XACL_SOLARIS_POSIX,
38 STREAM_XACL_SOLARIS_NFS4,
42 static const int os_default_acl_streams[] = {
47 * Define the supported XATTR streams for this OS
49 static const int os_xattr_streams[] = {
50 STREAM_XACL_SOLARIS_XATTR,
51 #if defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED)
52 STREAM_XACL_SOLARIS_SYS_XATTR,
53 #endif /* defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED) */
58 static const char *os_xattr_acl_skiplist[] = {
62 static const char *os_xattr_skiplist[] = {
64 #if defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED)
66 #endif /* defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED) */
71 * OS Specyfic constructor
73 XACL_Solaris::XACL_Solaris(){
75 set_acl_streams(os_acl_streams, os_default_acl_streams);
76 set_xattr_streams(os_xattr_streams);
77 set_xattr_skiplists(os_xattr_skiplist, os_xattr_acl_skiplist);
82 * OS Specyfic destructor
84 XACL_Solaris::~XACL_Solaris(){
90 * Checks if ACL's are available for a specified file
93 * jcr - Job Control Record
94 * name - specifies the system variable to be queried
96 * bRC_XACL_ok - check successful, lets setup xacltype variable
97 * bRC_XACL_error - in case of error
98 * bRC_XACL_skip - you should skip all other routine
100 bRC_XACL XACL_Solaris::check_xacltype (JCR *jcr, int name){
104 rc = pathconf(jcr->last_fname, name);
107 /* some error check why */
109 if (errno == ENOENT){
110 /* file does not exist skip it */
111 return bRC_XACL_skip;
113 Mmsg2(jcr->errmsg, _("pathconf error on file \"%s\": ERR=%s\n"), jcr->last_fname, be.bstrerror());
114 Dmsg2(100, "pathconf error file=%s ERR=%s\n", jcr->last_fname, be.bstrerror());
115 return bRC_XACL_error;
119 /* No support for ACLs */
120 clear_flag(XACL_FLAG_NATIVE);
122 return bRC_XACL_skip;
130 * Perform OS specyfic ACL backup
132 * in/out - check API at xacl.h
134 bRC_XACL XACL_Solaris::os_backup_acl (JCR *jcr, FF_PKT *ff_pkt){
140 * See if filesystem supports acls.
142 rc = check_xacltype(jcr, _PC_ACL_ENABLED);
153 rc = os_get_acl(jcr, &stream);
156 if (get_content_len() > 0){
157 if (send_acl_stream(jcr, stream) == bRC_XACL_fatal){
158 return bRC_XACL_fatal;
170 * Perform OS specyfic ACL restore
172 * in/out - check API at xacl.h
174 bRC_XACL XACL_Solaris::os_restore_acl (JCR *jcr, int stream, char *content, uint32_t length){
179 case STREAM_UNIX_ACCESS_ACL:
180 case STREAM_XACL_SOLARIS_POSIX:
181 case STREAM_XACL_SOLARIS_NFS4:
182 aclrc = pathconf(jcr->last_fname, _PC_ACL_ENABLED);
185 return bRC_XACL_error;
196 Mmsg2(jcr->errmsg, _("pathconf error on file \"%s\": ERR=%s\n"), jcr->last_fname, be.bstrerror());
197 Dmsg3(100, "pathconf error acl=%s file=%s ERR=%s\n", content, jcr->last_fname, be.bstrerror());
198 return bRC_XACL_error;
202 clear_flag(XACL_FLAG_NATIVE);
203 Mmsg(jcr->errmsg, _("Trying to restore acl on file \"%s\" on filesystem without acl support\n"), jcr->last_fname);
204 return bRC_XACL_error;
210 case STREAM_XACL_SOLARIS_POSIX:
211 if ((aclrc & (_ACL_ACLENT_ENABLED | _ACL_ACE_ENABLED)) == 0){
212 Mmsg(jcr->errmsg, _("Trying to restore POSIX acl on file \"%s\" on filesystem without aclent acl support\n"), jcr->last_fname);
213 return bRC_XACL_error;
216 case STREAM_XACL_SOLARIS_NFS4:
217 if ((aclrc & _ACL_ACE_ENABLED) == 0){
218 Mmsg(jcr->errmsg, _("Trying to restore NFSv4 acl on file \"%s\" on filesystem without ace acl support\n"), jcr->last_fname);
219 return bRC_XACL_error;
226 return os_set_acl(jcr, stream, content, length);
230 * Perform OS specyfic extended attribute backup
232 * in/out - check API at xacl.h
234 * The Solaris implementation of XATTR is very, very different then all other "generic" unix implementations,
235 * so the original author of the Bacula XATTR support for Solaris OS decided to totally change the Xattr Stream
236 * content, and we need to follow this design to support previous behavior. The stream consist of a number of
237 * "files" with STREAM_XACL_SOLARIS_XATTR or STREAM_XACL_SOLARIS_SYS_XATTR stream' id. Every singe stream represents
238 * a single attibute. The content is a NULL-terminated array with a following data:
239 * <xattr name>\0<encoded stat>\0<acl rendered text>\0<xattr data>
240 * when an attribute file has a hardlinked other attributes then a content stream changes a bit into:
241 * <xattr name>\0<encoded stat>\0<target xattr name>\0
243 * <xattr name> is an attribute name - a file name in Solaris
244 * <encoded stat> is a standard file stat struct encoded by Bacula (the same encoding goes with a regular file)
245 * <acl rendered text> is a Solaris dependent acltotext data
246 * <xattr data> is the attribute file raw content
247 * <target xattr name> is a name of the first hardlinked attribute file which a current attribute has to linked to
249 * The raw content of the attribute is copied into memory before send to the SD and for a very large attribute
250 * data can allocate a large amount of additional memory. In most cases it should not be a problem because most
251 * xattrs should has a few /hundred/ bytes in size. This is the same behavior as in previous implementation.
253 bRC_XACL XACL_Solaris::os_backup_xattr (JCR *jcr, FF_PKT *ff_pkt){
256 POOLMEM *xlist = NULL;
261 POOLMEM *value = NULL;
264 uint32_t xacltext_len;
265 POOLMEM *data = NULL;
268 char attribs[MAXSTRING];
273 /* sanity check of input variables */
274 if (jcr == NULL || ff_pkt == NULL){
275 return bRC_XACL_inval;
278 /* check if extended/extensible attributes are present */
279 if (pathconf(jcr->last_fname, _PC_XATTR_EXISTS) > 0){
280 /* xlist is allocated as POOLMEM by os_get_xattr_names */
281 rc = os_get_xattr_names(jcr, &xlist, &xlen);
284 /* it's ok, so go further */
288 /* no xattr available, so skip rest of it */
294 data = get_pool_memory(PM_BSOCK);
295 /* follow the list of xattr names and get the values */
296 for (name = xlist; (name - xlist) + 1 < xlen; name = strchr(name, '\0') + 1){
297 name_len = strlen(name);
298 /* skip read-only or other unused attribute names */
299 skip = check_xattr_skiplists(jcr, ff_pkt, name);
300 if (skip || name_len == 0){
301 Dmsg1(100, "Skipping xattr named \"%s\"\n", name);
304 /* set a correct stream */
305 stream = STREAM_XACL_SOLARIS_XATTR;
307 #if defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED)
308 /* check for system attributes name */
309 if (bstrcmp(name, VIEW_READWRITE)){
310 stream = STREAM_XACL_SOLARIS_SYS_XATTR;
312 #endif /* HAVE_SYS_NVPAIR_H && _PC_SATTR_ENABLED */
314 /* open an attribute descriptor, it will be used for backup */
315 attrfd = attropen(jcr->last_fname, name, O_RDONLY);
317 /* get the stat of the attribute */
318 if (fstat(attrfd, &st) < 0){
326 Mmsg3(jcr->errmsg, _("Unable to get status on xattr \"%s\" on file \"%s\": ERR=%s\n"), name, jcr->last_fname, be.bstrerror());
327 Dmsg3(100, "fstatat of xattr %s on \"%s\" failed: ERR=%s\n", name, jcr->last_fname, be.bstrerror());
333 /* we have a struct stat of the attribute so encode it to the buffer */
334 encode_stat(attribs, &st, sizeof(st), st.st_ino, stream);
336 /* get xattr acl data, but only when it is not trivial acls */
337 rc = os_get_xattr_acl(jcr, attrfd, &xacltext);
338 if (rc != bRC_XACL_ok){
341 xacltext_len = strlen(xacltext);
344 * Solaris support only S_IFREG and S_IFDIR as an attribute file type, no other types are supported
345 * the previous Solaris xattr implementation in Bacula had an unverified and untested code for other
346 * types of attribute files which was a nonsense and unnecessarily complicate the code. We decided
347 * to remove unsupported code. To check if the current Solaris version support for xattr was extended
348 * simply verify a man fsattr(5) for it.
350 switch (st.st_mode & S_IFMT){
352 /* check for hardlinked attributes which solaris support */
353 if (st.st_nlink > 1){
354 /* search for already saved file of the same inode number */
355 lnkname = find_xattr_cache(jcr, st.st_ino, name);
356 if (lnkname != NULL){
357 /* found a previous saved file, link to it and render xattr data for hardlinked attribute */
358 len = bsnprintf(data, sizeof_pool_memory(data), "%s%c%s%c%s%c", name, 0, attribs, 0, lnkname, 0);
359 set_content(data, len);
360 /* content is ready */
364 /* value is allocated as POOLMEM by os_get_xattr_value */
365 rc = os_get_xattr_value(jcr, name, &value, &value_len);
368 /* it's ok, so go further */
371 /* no xattr available, so skip rest of it */
378 /* save xattr info */
379 len = bsnprintf(data, sizeof_pool_memory(data), "%s%c%s%c%s%c", name, 0, attribs, 0, (xacltext) ? xacltext : "", 0);
380 /* append value data to the end of the xattr info */
381 check_pool_memory_size(data, len + value_len);
382 memcpy(data + len, value, value_len);
383 set_content(data,len + value_len);
384 free_pool_memory(value);
388 /* save xattr info */
389 len = bsnprintf(data, sizeof_pool_memory(data), "%s%c%s%c%s%c", name, 0, attribs, 0, (xacltext) ? xacltext : "", 0);
392 Mmsg3(jcr->errmsg, _("Unsupported extended attribute type: %i for \"%s\" on file \"%s\"\n"), st.st_mode & S_IFMT, name, jcr->last_fname);
393 Dmsg3(100, "Unsupported extended attribute type: %i for \"%s\" on file \"%s\"\n", st.st_mode & S_IFMT, name, jcr->last_fname);
397 /* send stream to the sd */
398 rc = send_xattr_stream(jcr, stream);
399 if (rc != bRC_XACL_ok){
400 Mmsg2(jcr->errmsg, _("Failed to send extended attribute \"%s\" on file \"%s\"\n"), name, jcr->last_fname);
401 Dmsg2(100, "Failed to send extended attribute \"%s\" on file \"%s\"\n", name, jcr->last_fname);
407 /* free allocated data: xlist, value (if not freed), data, etc. */
408 free_pool_memory(data);
410 free_pool_memory(value);
413 free_pool_memory(xlist);
415 /* this is a cache for a particular file, so no needed after backup of this file */
416 delete_xattr_cache();
424 * XACL_Solaris cache is a simple linked list cache of inode number and names used to handle
425 * xattr hard linked data. The function is searching for cached entry. When not found it append
426 * entry to the cache.
428 * jcr - Job Control Record (well, it is not used here)
429 * ino - inode number to compare/search for
430 * name - the name of the current attribute
432 * NULL - when entry not found in cache and new entry was added
433 * <str> - a name of the linked entry
435 inline char * XACL_Solaris::find_xattr_cache(JCR *jcr, ino_t ino, char * name){
437 XACL_Solaris_Cache *entry;
440 foreach_alist(entry, cache){
441 if (entry && entry->inode == ino){
442 /* found in cache, return name */
447 cache = New (alist(10, not_owned_by_alist));
449 /* not found, so add this one to the cache */
450 entry = (XACL_Solaris_Cache*) malloc (sizeof(XACL_Solaris_Cache));
453 cache->append(entry);
458 * The function deletes a cache
461 inline void XACL_Solaris::delete_xattr_cache(){
463 XACL_Solaris_Cache *entry;
466 foreach_alist(entry, cache){
475 * Perform OS specyfic XATTR restore. Runtime is called only when stream is supported by OS.
477 * The way Solaris xattr support is designed in Bacula we will have a single attribute restore
478 * with every call to this function. So multiple attributes are restored with multiple calls.
480 * in/out - check API at xacl.h
482 bRC_XACL XACL_Solaris::os_restore_xattr (JCR *jcr, int stream, char *content, uint32_t length){
484 bRC_XACL rc = bRC_XACL_error;
485 bool extended = false;
487 /* check input data */
488 if (jcr == NULL || content == NULL){
489 return bRC_XACL_inval;
492 /* First make sure we can restore xattr on the filesystem */
494 #if defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED)
495 case STREAM_XACL_SOLARIS_SYS_XATTR:
496 if (pathconf(jcr->last_fname, _PC_SATTR_ENABLED) <= 0){
497 Mmsg(jcr->errmsg, _("Failed to restore extensible attributes on file \"%s\"\n"), jcr->last_fname);
498 Dmsg1(100, "Unable to restore extensible attributes on file \"%s\", filesystem doesn't support this\n", jcr->last_fname);
504 case STREAM_XACL_SOLARIS_XATTR:
505 if (pathconf(jcr->last_fname, _PC_XATTR_ENABLED) <= 0){
506 Mmsg(jcr->errmsg, _("Failed to restore extended attributes on file \"%s\"\n"), jcr->last_fname);
507 Dmsg1(100, "Unable to restore extended attributes on file \"%s\", filesystem doesn't support this\n", jcr->last_fname);
515 rc = os_set_xattr(jcr, extended, content, length);
522 * Low level OS specyfic runtime to get ACL data from file. The ACL data is set in internal content buffer
524 * in/out - check API at xacl.h
526 bRC_XACL XACL_Solaris::os_get_acl(JCR *jcr, int *stream){
531 bRC_XACL rc = bRC_XACL_fatal;
534 return bRC_XACL_fatal;
537 if (acl_get(jcr->last_fname, ACL_NO_TRIVIAL, &aclp) != 0){
538 /* we've got some error */
542 /* file does not exist */
545 Mmsg2(jcr->errmsg, _("acl_get error on file \"%s\": ERR=%s\n"), jcr->last_fname, acl_strerror(errno));
546 Dmsg2(100, "acl_get error file=%s ERR=%s\n", jcr->last_fname, acl_strerror(errno));
547 return bRC_XACL_error;
553 * The ACLs simply reflect the (already known) standard permissions
554 * So we don't send an ACL stream to the SD.
560 #if defined(ACL_SID_FMT)
561 /* new format flag added in newer Solaris versions */
562 flags = ACL_APPEND_ID | ACL_COMPACT_FMT | ACL_SID_FMT;
564 flags = ACL_APPEND_ID | ACL_COMPACT_FMT;
565 #endif /* ACL_SID_FMT */
567 if ((acl_text = acl_totext(aclp, flags)) != NULL){
568 set_content(acl_text);
569 actuallyfree(acl_text);
571 switch (acl_type(aclp)){
573 *stream = STREAM_XACL_SOLARIS_POSIX;
576 *stream = STREAM_XACL_SOLARIS_NFS4;
589 * Low level OS specyfic runtime to get ACL on XATTR. The ACL data is set in supplied buffer
592 * jcr - Job Control Record
593 * fd - an opened file descriptor of the saved attribute
594 * buffer - a pointer to the memory buffer where we will render an acl text
596 * bRC_XACL_ok - backup acl for extended attribute finish without problems
597 * bRC_XACL_error - backup acl unsuccessful
598 * bRC_XACL_inval - input variables are invalid (null)
601 bRC_XACL XACL_Solaris::os_get_xattr_acl(JCR *jcr, int fd, char **buffer){
603 // a function is valid only when Bacula have a support for ACL
605 bRC_XACL rc = bRC_XACL_error;
607 /* sanity check of input variables */
608 if (jcr == NULL || buffer == NULL || *buffer == NULL || fd < 0){
609 return bRC_XACL_inval;
612 #ifdef HAVE_EXTENDED_ACL
617 /* check if an attribute has acl on it which we can save */
618 if (fpathconf(fd, _PC_ACL_ENABLED) > 0){
619 /* check for non trivial acl on the file */
620 if (facl_get(fd, ACL_NO_TRIVIAL, &aclp) != 0){
628 Mmsg2(jcr->errmsg, _("Unable to get xattr acl on file \"%s\": ERR=%s\n"), jcr->last_fname, be.bstrerror());
629 Dmsg2(100, "facl_get/acl_get of xattr on \"%s\" failed: ERR=%s\n", jcr->last_fname, be.bstrerror());
635 #if defined(ACL_SID_FMT)
636 /* New format flag added in newer Solaris versions. */
637 flags = ACL_APPEND_ID | ACL_COMPACT_FMT | ACL_SID_FMT;
639 flags = ACL_APPEND_ID | ACL_COMPACT_FMT;
640 #endif /* ACL_SID_FMT */
642 *buffer = acl_totext(aclp, flags);
653 #else /* !HAVE_EXTENDED_ACL */
656 aclent_t *acls = NULL;
658 /* See if this attribute has an ACL */
660 n = facl(fd, GETACLCNT, 0, NULL);
662 n = acl(attrname, GETACLCNT, 0, NULL);
665 if (n >= MIN_ACL_ENTRIES){
666 acls = (aclent_t *)malloc(n * sizeof(aclent_t));
667 if ((fd != -1 && facl(fd, GETACL, n, acls) != n) ||
668 acl(attrname, GETACL, n, acls) != n){
674 retval = bRC_XACL_ok;
677 Mmsg3(jcr->errmsg, _("Unable to get acl on xattr %s on file \"%s\": ERR=%s\n"), attrname, jcr->last_fname, be.bstrerror());
678 Dmsg3(100, "facl/acl of xattr %s on \"%s\" failed: ERR=%s\n", attrname, jcr->last_fname, be.bstrerror());
684 /* See if there is a non trivial acl on the file. */
685 if (!acl_is_trivial(n, acls)){
686 if ((*acl_text = acltotext(acls, n)) == NULL){
689 Mmsg3(jcr->errmsg, _("Unable to get acl text on xattr %s on file \"%s\": ERR=%s\n"), attrname, jcr->last_fname, be.bstrerror());
690 Dmsg3(100, "acltotext of xattr %s on \"%s\" failed: ERR=%s\n", attrname, jcr->last_fname, be.bstrerror());
703 #endif /* HAVE_EXTENDED_ACL */
707 #endif /* HAVE_ACL */
711 * Low level OS specyfic runtime to set ACL on XATTR. The ACL data is set from supplied text
714 * jcr - Job Control Record
715 * fd - an opened file descriptor of the restored attribute
716 * buffer - a pointer to the memory buffer where we will render an acl text
718 * bRC_XACL_ok - backup acl for extended attribute finish without problems
719 * bRC_XACL_inval - input variables are invalid (null)
722 bRC_XACL XACL_Solaris::os_set_xattr_acl(JCR *jcr, int fd, char *name, char *acltext){
724 // a function is valid only when Bacula have a support for ACL
727 bRC_XACL rc = bRC_XACL_error;
729 /* sanity check of input variables */
730 if (jcr == NULL || name == NULL || acltext == NULL || fd < 0){
731 return bRC_XACL_inval;
734 #ifdef HAVE_EXTENDED_ACL
739 if ((error = acl_fromtext(acltext, &aclp)) != 0){
740 Mmsg1(jcr->errmsg, _("Unable to convert acl from text on file \"%s\"\n"), jcr->last_fname);
741 return bRC_XACL_error;
744 if (fd != -1 && facl_set(fd, aclp) != 0){
747 Mmsg3(jcr->errmsg, _("Unable to restore acl of xattr %s on file \"%s\": ERR=%s\n"), name, jcr->last_fname, be.bstrerror());
748 Dmsg3(100, "Unable to restore acl of xattr %s on file \"%s\": ERR=%s\n", name, jcr->last_fname, be.bstrerror());
757 #else /* !HAVE_EXTENDED_ACL */
760 aclent_t *acls = NULL;
762 acls = aclfromtext(acltext, &n);
764 if (fd != -1 && facl(fd, SETACL, n, acls) != 0){
767 Mmsg3(jcr->errmsg, _("Unable to restore acl of xattr %s on file \"%s\": ERR=%s\n"), name, jcr->last_fname, be.bstrerror());
768 Dmsg3(100, "Unable to restore acl of xattr %s on file \"%s\": ERR=%s\n", name, jcr->last_fname, be.bstrerror());
774 #endif /* HAVE_EXTENDED_ACL */
779 #endif /* HAVE_ACL */
783 * Low level OS specyfic runtime to set ACL data on file
785 * in/out - check API at xacl.h
787 bRC_XACL XACL_Solaris::os_set_acl(JCR *jcr, int stream, char *content, uint32_t length){
792 if ((rc = acl_fromtext(content, &aclp)) != 0){
793 Mmsg2(jcr->errmsg, _("acl_fromtext error on file \"%s\": ERR=%s\n"), jcr->last_fname, acl_strerror(rc));
794 Dmsg3(100, "acl_fromtext error acl=%s file=%s ERR=%s\n", content, jcr->last_fname, acl_strerror(rc));
795 return bRC_XACL_error;
799 case STREAM_XACL_SOLARIS_POSIX:
800 if (acl_type(aclp) != ACLENT_T){
801 Mmsg(jcr->errmsg, _("wrong encoding of acl type in acl stream on file \"%s\"\n"), jcr->last_fname);
802 return bRC_XACL_error;
805 case STREAM_XACL_SOLARIS_NFS4:
806 if (acl_type(aclp) != ACE_T){
807 Mmsg(jcr->errmsg, _("wrong encoding of acl type in acl stream on file \"%s\"\n"), jcr->last_fname);
808 return bRC_XACL_error;
815 if ((rc = acl_set(jcr->last_fname, aclp)) == -1 && jcr->last_type != FT_LNK){
821 Mmsg2(jcr->errmsg, _("acl_set error on file \"%s\": ERR=%s\n"), jcr->last_fname, acl_strerror(rc));
822 Dmsg3(100, "acl_set error acl=%s file=%s ERR=%s\n", content, jcr->last_fname, acl_strerror(rc));
824 return bRC_XACL_error;
833 * Return a list of xattr names in newly allocated pool memory and a length of the allocated buffer.
834 * It allocates a memory with poolmem subroutines every time a function is called, so it must be freed
837 * in/out - check API at xacl.h
839 bRC_XACL XACL_Solaris::os_get_xattr_names (JCR *jcr, POOLMEM ** pxlist, uint32_t * xlen){
850 /* check input data */
851 if (jcr == NULL || xlen == NULL || pxlist == NULL){
852 return bRC_XACL_inval;
855 /* Open the xattr stream on file */
856 if ((xattrdfd = attropen(jcr->last_fname, ".", O_RDONLY)) < 0){
861 /* no file available, skip it */
862 return bRC_XACL_skip;
864 /* no xattr supported on file skip it */
865 return bRC_XACL_skip;
867 Mmsg2(jcr->errmsg, _("Unable to open xattr on file \"%s\": ERR=%s\n"), jcr->last_fname, be.bstrerror());
868 Dmsg2(100, "Unable to open xattr on file \"%s\": ERR=%s\n", jcr->last_fname, be.bstrerror());
869 return bRC_XACL_error;
873 /* open an extended file directory to read all xattr names */
874 if ((dirp = fdopendir(xattrdfd)) == (DIR *)NULL){
877 Mmsg2(jcr->errmsg, _("Unable to list the xattr on file \"%s\": ERR=%s\n"), jcr->last_fname, be.bstrerror());
878 Dmsg3(100, "Unable to fdopendir xattr on file \"%s\" using fd %d: ERR=%s\n", jcr->last_fname, xattrdfd, be.bstrerror());
880 return bRC_XACL_error;
884 * allocate memory for the extented attribute list
885 * default size is a 4k for PM_BSOCK, which should be sufficient in most cases
887 list = p = get_pool_memory(PM_BSOCK);
888 memset(list, 0, sizeof_pool_memory(list));
891 /* read all directory entries as a xattr names */
892 while ((dp = readdir(dirp)) != NULL){
894 /* skip '..' name as it a file we backup */
895 if (bstrcmp(dp->d_name, "..") == 0){
899 #if defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED)
900 /* skip a read only attributes which we cant restore later */
901 if (bstrcmp(dp->d_name, VIEW_READONLY)){
902 Dmsg2(400, "Skipping readonly extensible attributes %s on file \"%s\"\n", dp->d_name, jcr->last_fname);
905 #endif /* HAVE_SYS_NVPAIR_H && _PC_SATTR_ENABLED */
907 /* compute a buffer length = string length and nul char */
908 slen = strlen (dp->d_name);
910 list = check_pool_memory_size(list, len);
912 /* copy the name into a list */
913 bstrncpy(p, dp->d_name, slen);
917 if (closedir(dirp) < 0){
920 Mmsg2(jcr->errmsg, _("Unable to close xattr list on file \"%s\": ERR=%s\n"), jcr->last_fname, be.bstrerror());
921 Dmsg2(100, "Unable to close xattr list on file \"%s\": ERR=%s\n", jcr->last_fname, be.bstrerror());
922 return bRC_XACL_error;
932 * Return a value of the requested attribute name and a length of the allocated buffer.
933 * It allocates a memory with poolmem subroutines every time a function is called, so it must be freed
936 * in/out - check API at xacl.h
938 bRC_XACL XACL_Solaris::os_get_xattr_value (JCR *jcr, char * name, char ** pvalue, uint32_t * plen){
945 /* check input data */
946 if (jcr == NULL || name == NULL || plen == NULL || pvalue == NULL){
947 return bRC_XACL_inval;
950 /* Open the xattr on file */
951 if ((xattrfd = attropen(jcr->last_fname, name, O_RDONLY)) < 0){
956 /* no file available, skip it */
957 return bRC_XACL_skip;
959 /* no xattr supported on file skip it */
960 return bRC_XACL_skip;
962 Mmsg2(jcr->errmsg, _("Unable to open xattr on file \"%s\": ERR=%s\n"), jcr->last_fname, be.bstrerror());
963 Dmsg2(100, "Unable to open xattr on file \"%s\": ERR=%s\n", jcr->last_fname, be.bstrerror());
964 return bRC_XACL_error;
968 /* get some info about extended attribute */
969 if (fstat(xattrfd, &st) < 0){
974 /* no file available, skip it */
975 return bRC_XACL_skip;
977 Mmsg3(jcr->errmsg, _("Unable to stat xattr \"%s\" on file \"%s\": ERR=%s\n"), name, jcr->last_fname, be.bstrerror());
978 Dmsg3(100, "Unable to stat xattr \"%s\" on file \"%s\": ERR=%s\n", name, jcr->last_fname, be.bstrerror());
979 return bRC_XACL_error;
983 /* default empty value */
987 /* only a file has a data/value we should care about */
988 if ((st.st_mode & S_IFMT) != S_IFDIR){
989 /* get size of the attribute data/value */
990 len = lseek(xattrfd, 0, SEEK_END);
991 lseek(xattrfd, 0, SEEK_SET);
995 * allocate memory for the extented attribute value
996 * default size is a 256B for PM_MESSAGE, so we need to check required size
998 value = get_pool_memory(PM_MESSAGE);
999 value = check_pool_memory_size(value, len);
1000 memset(value, 0, len);
1002 read (xattrfd, value, len);
1006 /* setup return data */
1013 * Low level OS specyfic runtime to set extended attribute on file
1015 * in/out - check API at xacl.h
1017 bRC_XACL XACL_Solaris::os_set_xattr (JCR *jcr, bool extended, char *content, uint32_t length){
1019 char *bp = content + 1; /* original code saves attribute name with '/' */
1030 struct timeval times[2];
1031 bRC_XACL rc = bRC_XACL_ok;
1033 /* check input data */
1034 if (jcr == NULL || content == NULL){
1035 return bRC_XACL_inval;
1038 * Parse content stream and extract valuable data.
1039 * STD/EXT: <xattr name>\0<encoded stat>\0<acl rendered text>\0<xattr data>
1040 * LNK: <xattr name>\0<encoded stat>\0<target xattr name>\0
1042 /* attribute name and length */
1047 /* attribute encoded stat */
1052 decode_stat(attribs, &st, sizeof(st), &inum);
1054 /* acltext and link target name goes here */
1055 acltext = lntarget = bp;
1057 /* now 'bp' should have a xattr data */
1061 * Open the xattr on which to restore the xattrs read-only.
1063 if ((attrdirfd = attropen(jcr->last_fname, ".", O_RDONLY)) < 0){
1066 Mmsg2(jcr->errmsg, _("Unable to open file \"%s\": ERR=%s\n"), jcr->last_fname, be.bstrerror());
1067 Dmsg2(100, "Unable to open file \"%s\": ERR=%s\n", jcr->last_fname, be.bstrerror());
1068 rc = bRC_XACL_error;
1072 switch (st.st_mode & S_IFMT){
1075 /* it is a linked attribute, perform a link operation */
1076 unlinkat(attrdirfd, name, 0);
1077 if (link(lntarget, name) < 0){
1080 Mmsg4(jcr->errmsg, _("Unable to link xattr %s to %s on file \"%s\": ERR=%s\n"), name, lntarget, jcr->last_fname, be.bstrerror());
1081 Dmsg4(100, "Unable to link xattr %s to %s on file \"%s\": ERR=%s\n", name, lntarget, jcr->last_fname, be.bstrerror());
1082 rc = bRC_XACL_error;
1088 unlinkat(attrdirfd, name, 0);
1090 if ((attrfd = openat(attrdirfd, name, O_CREAT|O_RDWR)) < 0){
1093 Mmsg3(jcr->errmsg, _("Unable to open attribute \"%s\" at file \"%s\": ERR=%s\n"), name, jcr->last_fname, be.bstrerror());
1094 Dmsg3(100, "Unable to open attribute \"%s\" at file \"%s\": ERR=%s\n", name, jcr->last_fname, be.bstrerror());
1095 rc = bRC_XACL_error;
1098 /* restore any data if are available */
1099 if (st.st_size > 0){
1100 cnt = write (attrfd, bp, length - (bp - content) );
1104 Mmsg3(jcr->errmsg, _("Unable to restore data of xattr %s on file \"%s\": ERR=%s\n"), name, jcr->last_fname, be.bstrerror());
1105 Dmsg3(100, "Unable to restore data of xattr %s on file \"%s\": ERR=%s\n", name, jcr->last_fname, be.bstrerror());
1106 rc = bRC_XACL_error;
1113 /* if it is a current dir ob file then we can restore acl data only */
1114 if (bstrcmp(name, ".")){
1118 Mmsg2(jcr->errmsg, _("Unsupported xattr type %s on file \"%s\"\n"), name, jcr->last_fname);
1119 Dmsg2(100, "Unsupported xattr type %s on file \"%s\"\n", name, jcr->last_fname);
1123 /* file data restored, so setup permissions and acl data */
1125 if (fchownat(attrdirfd, name, st.st_uid, st.st_gid, AT_SYMLINK_NOFOLLOW) < 0){
1133 Mmsg3(jcr->errmsg, _("Unable to restore owner of xattr %s on file \"%s\": ERR=%s\n"), name, jcr->last_fname, be.bstrerror());
1134 Dmsg3(100, "Unable to restore owner of xattr %s on file \"%s\": ERR=%s\n", name, jcr->last_fname, be.bstrerror());
1135 rc = bRC_XACL_error;
1142 if (strlen(acltext)){
1143 rc = os_set_xattr_acl(jcr, attrfd, name, acltext);
1144 if (rc != bRC_XACL_ok){
1148 #endif /* HAVE_ACL */
1150 /* now restore a access and modification time - only for standard attribute */
1152 times[0].tv_sec = st.st_atime;
1153 times[0].tv_usec = 0;
1154 times[1].tv_sec = st.st_mtime;
1155 times[1].tv_usec = 0;
1157 if (futimesat(attrdirfd, name, times) < 0){
1160 Mmsg3(jcr->errmsg, _("Unable to restore filetimes of xattr %s on file \"%s\": ERR=%s\n"), name, jcr->last_fname, be.bstrerror());
1161 Dmsg3(100, "Unable to restore filetimes of xattr %s on file \"%s\": ERR=%s\n", name, jcr->last_fname, be.bstrerror());
1162 rc = bRC_XACL_error;
1171 if (attrdirfd != 0){
1177 #endif /* HAVE_SUN_OS */