Esempio n. 1
0
ssize_t sys_lgetxattr (const char *path, const char *uname, void *value, size_t size)
{
	const char *name = prefix(uname);

#if defined(HAVE_LGETXATTR)
	return lgetxattr(path, name, value, size);
#elif defined(HAVE_GETXATTR) && defined(XATTR_ADD_OPT)
	int options = XATTR_NOFOLLOW;
	return getxattr(path, name, value, size, 0, options);
#elif defined(HAVE_LGETEA)
	return lgetea(path, name, value, size);
#elif defined(HAVE_EXTATTR_GET_LINK)
	ssize_t retval;

	retval = extattr_get_link(path, EXTATTR_NAMESPACE_USER, uname, NULL, 0);
    if (retval == -1) {
        LOG(log_maxdebug, logtype_default, "extattr_get_link(): %s",
            strerror(errno));
        return -1;
    }
    if (size == 0)
        /* Only interested in size of xattr */
        return retval;
    if (retval > size) {
        errno = ERANGE;
        return -1;
    }
    return extattr_get_link(path, EXTATTR_NAMESPACE_USER, uname, value, size);

#elif defined(HAVE_ATTR_GET)
	int retval, flags = ATTR_DONTFOLLOW;
	int valuelength = (int)size;
	char *attrname = strchr(name,'.') + 1;
	
	if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT;

	retval = attr_get(path, attrname, (char *)value, &valuelength, flags);

	return retval ? retval : valuelength;
#elif defined(HAVE_ATTROPEN)
	ssize_t ret = -1;
	int attrfd = solaris_attropen(path, name, O_RDONLY | O_NOFOLLOW, 0);
	if (attrfd >= 0) {
		ret = solaris_read_xattr(attrfd, value, size);
		close(attrfd);
	}
	return ret;
#else
	errno = ENOSYS;
	return -1;
#endif
}
Esempio n. 2
0
int sys_lsetxattr (const char *path, const char *uname, const void *value, size_t size, int flags)
{
	const char *name = prefix(uname);
#if defined(HAVE_LSETXATTR)
	return lsetxattr(path, name, value, size, flags);
#elif defined(HAVE_SETXATTR) && defined(XATTR_ADD_OPT)
	int options = XATTR_NOFOLLOW;
	return setxattr(path, name, value, size, 0, options);
#elif defined(LSETEA)
	return lsetea(path, name, value, size, flags);
#elif defined(HAVE_EXTATTR_SET_LINK)
	int retval = 0;
	if (flags) {
		/* Check attribute existence */
		retval = extattr_get_link(path, EXTATTR_NAMESPACE_USER, uname, NULL, 0);
		if (retval < 0) {
			/* REPLACE attribute, that doesn't exist */
			if (flags & XATTR_REPLACE && errno == ENOATTR) {
				errno = ENOATTR;
				return -1;
			}
			/* Ignore other errors */
		}
		else {
			/* CREATE attribute, that already exists */
			if (flags & XATTR_CREATE) {
				errno = EEXIST;
				return -1;
			}
		}
	}

	retval = extattr_set_link(path, EXTATTR_NAMESPACE_USER, uname, value, size);
	return (retval < 0) ? -1 : 0;
#elif defined(HAVE_ATTR_SET)
	int myflags = ATTR_DONTFOLLOW;
	char *attrname = strchr(name,'.') + 1;
	
	if (strncmp(name, "system", 6) == 0) myflags |= ATTR_ROOT;
	if (flags & XATTR_CREATE) myflags |= ATTR_CREATE;
	if (flags & XATTR_REPLACE) myflags |= ATTR_REPLACE;

	return attr_set(path, attrname, (const char *)value, size, myflags);
#elif defined(HAVE_ATTROPEN)
	int ret = -1;
	int myflags = O_RDWR | AT_SYMLINK_NOFOLLOW;
	int attrfd;
	if (flags & XATTR_CREATE) myflags |= O_EXCL;
	if (!(flags & XATTR_REPLACE)) myflags |= O_CREAT;
	attrfd = solaris_attropen(path, name, myflags, (mode_t) SOLARIS_ATTRMODE);
	if (attrfd >= 0) {
		ret = solaris_write_xattr(attrfd, value, size);
		close(attrfd);
	}
	return ret;
#else
	errno = ENOSYS;
	return -1;
#endif
}
Esempio n. 3
0
static PyObject *
lgetxattr_wrapper(PyObject *self, PyObject *args)
{
    const char *filename;
    const char *attrname;
    size_t bufsize;
    PyObject *o;

    if (!PyArg_ParseTuple(args, "ss", &filename, &attrname))
        return NULL;

    bufsize = 0;
    o = NULL;
    do {
        bufsize += 1024;
        char *buf = malloc(bufsize);
        if (buf == NULL) {
            Py_INCREF(Py_None);
            return Py_None;
        }
#ifdef __FreeBSD__
        int n = extattr_get_link(filename, EXTATTR_NAMESPACE_USER,
                                 attrname, buf, bufsize);
#else
        ssize_t n = lgetxattr(filename, attrname, buf, bufsize);
#endif
        if (n >= 0)
            o = Py_BuildValue("s#", buf, (int) n);
        else if (n == -1 && errno != ERANGE)
            o = Py_BuildValue("i", errno);
        free(buf);
    } while (o == NULL);

    return o;
}
Esempio n. 4
0
static ssize_t xattr_getxattr(const char *path, const char *name,
                              void *value, ssize_t size, u_int32_t position,
                              int options)
{
    if (position != 0 ||
        !(options == 0 || options == XATTR_XATTR_NOFOLLOW)) {
        return -1;
    }

    if (options & XATTR_XATTR_NOFOLLOW) {
        return extattr_get_link(path, EXTATTR_NAMESPACE_USER,
                                name, value, size);
    }
    else {
        return extattr_get_file(path, EXTATTR_NAMESPACE_USER,
                                name, value, size);
    }
}
Esempio n. 5
0
int
main(int argc, char *argv[])
{
	char	*buf, *visbuf, *p;

	const char *options, *attrname;
	size_t	len;
	ssize_t	ret;
	int	 buflen, visbuflen, ch, error, i, arg_counter, attrnamespace,
		 minargc;

	int	flag_force = 0;
	int	flag_nofollow = 0;
	int	flag_null = 0;
	int	flag_quiet = 0;
	int	flag_string = 0;
	int	flag_hex = 0;

	visbuflen = buflen = 0;
	visbuf = buf = NULL;

	p = basename(argv[0]);
	if (p == NULL)
		p = argv[0];
	if (!strcmp(p, "getextattr")) {
		what = EAGET;
		options = "fhqsx";
		minargc = 3;
	} else if (!strcmp(p, "setextattr")) {
		what = EASET;
		options = "fhnq";
		minargc = 4;
	} else if (!strcmp(p, "rmextattr")) {
		what = EARM;
		options = "fhq";
		minargc = 3;
	} else if (!strcmp(p, "lsextattr")) {
		what = EALS;
		options = "fhq";
		minargc = 2;
	} else {
		usage();
	}

	while ((ch = getopt(argc, argv, options)) != -1) {
		switch (ch) {
		case 'f':
			flag_force = 1;
			break;
		case 'h':
			flag_nofollow = 1;
			break;
		case 'n':
			flag_null = 1;
			break;
		case 'q':
			flag_quiet = 1;
			break;
		case 's':
			flag_string = 1;
			break;
		case 'x':
			flag_hex = 1;
			break;
		case '?':
		default:
			usage();
		}
	}

	argc -= optind;
	argv += optind;

	if (argc < minargc)
		usage();

	error = extattr_string_to_namespace(argv[0], &attrnamespace);
	if (error)
		err(-1, "%s", argv[0]);
	argc--; argv++;

	if (what != EALS) {
		attrname = argv[0];
		argc--; argv++;
	} else
		attrname = NULL;

	if (what == EASET) {
		mkbuf(&buf, &buflen, strlen(argv[0]) + 1);
		strcpy(buf, argv[0]);
		argc--; argv++;
	}

	for (arg_counter = 0; arg_counter < argc; arg_counter++) {
		switch (what) {
		case EARM:
			if (flag_nofollow)
				error = extattr_delete_link(argv[arg_counter],
				    attrnamespace, attrname);
			else
				error = extattr_delete_file(argv[arg_counter],
				    attrnamespace, attrname);
			if (error >= 0)
				continue;
			break;
		case EASET:
			len = strlen(buf) + flag_null;
			if (flag_nofollow)
				ret = extattr_set_link(argv[arg_counter],
				    attrnamespace, attrname, buf, len);
			else
				ret = extattr_set_file(argv[arg_counter],
				    attrnamespace, attrname, buf, len);
			if (ret >= 0) {
				if ((size_t)ret != len && !flag_quiet) {
					warnx("Set %zd bytes of %zu for %s",
					    ret, len, attrname);
				}
				continue;
			}
			break;
		case EALS:
			if (flag_nofollow)
				ret = extattr_list_link(argv[arg_counter],
				    attrnamespace, NULL, 0);
			else
				ret = extattr_list_file(argv[arg_counter],
				    attrnamespace, NULL, 0);
			if (ret < 0)
				break;
			mkbuf(&buf, &buflen, ret);
			if (flag_nofollow)
				ret = extattr_list_link(argv[arg_counter],
				    attrnamespace, buf, buflen);
			else
				ret = extattr_list_file(argv[arg_counter],
				    attrnamespace, buf, buflen);
			if (ret < 0)
				break;
			if (!flag_quiet)
				printf("%s\t", argv[arg_counter]);
			for (i = 0; i < ret; i += ch + 1) {
			    /* The attribute name length is unsigned. */
			    ch = (unsigned char)buf[i];
			    printf("%s%*.*s", i ? "\t" : "",
				ch, ch, buf + i + 1);
			}
			if (!flag_quiet || ret > 0)
				printf("\n");
			continue;
		case EAGET:
			if (flag_nofollow)
				ret = extattr_get_link(argv[arg_counter],
				    attrnamespace, attrname, NULL, 0);
			else
				ret = extattr_get_file(argv[arg_counter],
				    attrnamespace, attrname, NULL, 0);
			if (ret < 0)
				break;
			mkbuf(&buf, &buflen, ret);
			if (flag_nofollow)
				ret = extattr_get_link(argv[arg_counter],
				    attrnamespace, attrname, buf, buflen);
			else
				ret = extattr_get_file(argv[arg_counter],
				    attrnamespace, attrname, buf, buflen);
			if (ret < 0)
				break;
			if (!flag_quiet)
				printf("%s\t", argv[arg_counter]);
			if (flag_string) {
				mkbuf(&visbuf, &visbuflen, ret * 4 + 1);
				strvisx(visbuf, buf, ret,
				    VIS_SAFE | VIS_WHITE);
				printf("\"%s\"\n", visbuf);
				continue;
			} else if (flag_hex) {
				for (i = 0; i < ret; i++)
					printf("%s%02x", i ? " " : "",
					    buf[i]);
				printf("\n");
				continue;
			} else {
				fwrite(buf, ret, 1, stdout);
				printf("\n");
				continue;
			}
		default:
			break;
		}
		if (!flag_quiet) 
			warn("%s: failed", argv[arg_counter]);
		if (flag_force)
			continue;
		return(1);
	}
	return (0);
}
Esempio n. 6
0
ssize_t sys_lgetxattr(const char *path, const char *name, void *value, size_t size)
{
	return extattr_get_link(path, EXTATTR_NAMESPACE_USER, name, value, size);
}
Esempio n. 7
0
File: xattr.c Progetto: EmisFR/burp
int get_xattr(struct asfd *asfd, const char *path,
	char **xattrtext, size_t *xlen, struct cntr *cntr)
{
	int i=0;
	ssize_t maxlen=0xFFFFFFFF/2;

	for(i=0; i<(int)(sizeof(namespaces)/sizeof(int)); i++)
	{
		int j=0;
		ssize_t len=0;
		int have_acl=0;
		char *xattrlist=NULL;
		char *cnamespace=NULL;
		ssize_t totallen=0;
		char *toappend=NULL;
		char z[BSD_BUF_SIZE]="";
		char cattrname[BSD_BUF_SIZE]="";
		if((len=extattr_list_link(path, namespaces[i], NULL, 0))<0)
		{
			logw(asfd, cntr, "could not extattr_list_link of '%s': %zd\n",
				path, len);
			return 0; // carry on
		}
		if(!len) continue;
		if(xattrtext && *xattrtext)
		{
			// Already have some meta text, which means that some
			// ACLs were set.
			have_acl++;
		}
		if(!(xattrlist=(char *)calloc_w(1, len+1, __func__)))
			return -1;
		if((len=extattr_list_link(path, namespaces[i], xattrlist, len))<=0)
		{
			logw(asfd, cntr, "could not extattr_list_link '%s': %zd\n",
				path, len);
			free_w(&xattrlist);
			return 0; // carry on
		}
		xattrlist[len]='\0';

		if(extattr_namespace_to_string(namespaces[i], &cnamespace))
		{
			logp("Failed to convert %d into namespace on '%s'\n",
				 namespaces[i], path);
			free_w(&xattrlist);
			return 0; // carry on
		}


		for(j=0; j<(int)len; j+=xattrlist[j]+1)
		{
			int cnt=0;
			char tmp1[9];
			char tmp2[9];
			size_t newlen=0;
			size_t zlen=0;
			ssize_t vlen=0;
			char *val=NULL;
			cnt=xattrlist[j];
			if(cnt>((int)sizeof(cattrname)-1))
				cnt=((int)sizeof(cattrname)-1);
			strncpy(cattrname, xattrlist+(j+1), cnt);
			cattrname[cnt]='\0';
			snprintf(z, sizeof(z), "%s.%s",
				cnamespace, cattrname);

			if(have_acl && in_skiplist(z))
				continue;
			zlen=strlen(z);
			//printf("\ngot: %s (%s)\n", z, path);

			if((vlen=extattr_list_link(path, namespaces[i],
				xattrlist, len))<0)
			{
				logw(asfd, cntr, "could not extattr_list_link on %s for %s: %zd\n", path, cnamespace, vlen);
				continue;
			}
			if(vlen)
			{
				if(!(val=(char *)malloc_w(vlen+1, __func__)))
				{
					free_w(&xattrlist);
					free_w(&toappend);
					return -1;
				}
				if((vlen=extattr_get_link(path, namespaces[i],
					cattrname, val, vlen))<0)
				{
					logw(asfd, cntr, "could not extattr_list_link %s for %s: %zd\n", path, cnamespace, vlen);
					free_w(&val);
					continue;
				}
				val[vlen]='\0';

				if(vlen>maxlen)
				{
					logw(asfd, cntr, "xattr value of '%s' too long: %zd\n",
						path, vlen);
					free_w(&toappend);
					free_w(&val);
					break;
				}
			}

			snprintf(tmp1, sizeof(tmp1), "%08X", (unsigned int)zlen);
			snprintf(tmp2, sizeof(tmp2), "%08X", (unsigned int)vlen);
			newlen=totallen+8+zlen+8+vlen;
			if(!(toappend=(char *)realloc_w(toappend, newlen, __func__)))
			{
				free_w(&val);
				free_w(&xattrlist);
				return -1;
			}
			memcpy(toappend+totallen, tmp1, 8);
			totallen+=8;
			memcpy(toappend+totallen, z, zlen);
			totallen+=zlen;
			memcpy(toappend+totallen, tmp2, 8);
			totallen+=8;
			memcpy(toappend+totallen, val, vlen);
			totallen+=vlen;
			free_w(&val);

			if(totallen>maxlen)
			{
				logw(asfd, cntr,
				  "xattr length of '%s' grew too long: %lu\n",
				  path, (unsigned long)totallen);
				free_w(&val);
				free_w(&toappend);
				free_w(&xattrlist);
				return 0; // carry on
			}
		}

		if(toappend)
		{
			if(append_to_extrameta(toappend, META_XATTR_BSD,
				xattrtext, xlen, totallen))
			{
				free_w(&toappend);
				free_w(&xattrlist);
				return -1;
			}
		}
		free_w(&toappend);
		free_w(&xattrlist);
	}

	return 0;
}
Esempio n. 8
0
/* Obtain the Extended Attributes and/or the ACLs of the given file in a form
   that is ready for aaip_encode().
   @param path          Path to the file
   @param num_attrs     Will return the number of name-value pairs
   @param names         Will return an array of pointers to 0-terminated names
   @param value_lengths Will return an arry with the lenghts of values
   @param values        Will return an array of pointers to 8-bit values
   @param flag          Bitfield for control purposes
                        bit0=  obtain ACL (access and eventually default)
                        bit1=  use numeric ACL qualifiers rather than names
                        bit2=  do not obtain attributes other than ACL
                        bit3=  do not ignore eventual non-user attributes
                               I.e. those with a name which does not begin
                               by "user."
                        bit4=  do not return trivial ACL that matches st_mode
                        bit5=  in case of symbolic link: inquire link target
                        bit15= free memory of names, value_lengths, values
   @return              >0  ok
                        <=0 error
                        -1= out of memory
                        -2= program error with prediction of result size
                        -3= error with conversion of name to uid or gid
*/
int aaip_get_attr_list(char *path, size_t *num_attrs, char ***names,
                       size_t **value_lengths, char ***values, int flag)
{
 int ret;
 ssize_t i, num_names= 0, acl_names= 0;

#ifdef Libisofs_with_aaip_acL
 unsigned char *a_acl= NULL;
 char *a_acl_text= NULL;
 size_t a_acl_len= 0;
#endif
#ifdef Libisofs_with_freebsd_extattR
 char *list= NULL, *user_list= NULL, *sys_list= NULL, *namept;
 ssize_t value_ret, retry= 0, list_size= 0, user_list_size= 0;
 ssize_t sys_list_size= 0;
 int attrnamespace;
#endif

 if(flag & (1 << 15)) { /* Free memory */
   {ret= 1; goto ex;}
 }

 *num_attrs= 0;
 *names= NULL;
 *value_lengths= NULL;
 *values= NULL;

 /* Set up arrays */

#ifdef Libisofs_with_freebsd_extattR

 if(!(flag & 4)) { /* Get extattr names */

   /* Linux  : Names are encoded as name NUL
      FreeBSD: Names are encoded as length_byte:chars (no NUL)
      AAIP demands names not to contain NUL bytes. 
   */

   /* Obtain lists of names
      Must be done separately for namespaces. See man 9 extattr :
      EXTATTR_NAMESPACE_USER , EXTATTR_NAMESPACE_SYSTEM
      Must then be marked by "user." and "system." for libisofs use.
   */
   ret= aaip_extattr_make_list(path, EXTATTR_NAMESPACE_USER,
                               &user_list, &user_list_size, flag & 32);
   if(ret <= 0)
     {ret= -1; goto ex;}
   if(flag & 8) {
     ret= aaip_extattr_make_list(path, EXTATTR_NAMESPACE_SYSTEM,
                                 &sys_list, &sys_list_size, flag & 32);
     if(ret <= 0)
       {ret= -1; goto ex;}
   }

   /* Check for NUL in names, convert into a linuxish list of namespace.name */
   ret= aaip_extattr_make_namelist(path, "user", user_list, user_list_size,
                                   &list, &list_size, &num_names, 0);
   if(ret <= 0)
     goto ex;
   ret= aaip_extattr_make_namelist(path, "system", sys_list, sys_list_size,
                                   &list, &list_size, &num_names, 1);
   if(ret <= 0)
     goto ex;
 }

#endif /* Libisofs_with_freebsd_extattR */

#ifdef Libisofs_with_aaip_acL
 if(flag & 1) {
   num_names++;
   acl_names= 1;
 }
#endif
 
 if(num_names == 0)
   {ret= 1; goto ex;}
 (*names)= calloc(num_names, sizeof(char *));
 (*value_lengths)= calloc(num_names, sizeof(size_t));
 (*values)= calloc(num_names, sizeof(char *));
 if(*names == NULL || *value_lengths == NULL || *values == NULL)
   {ret= -1; goto ex;}

 for(i= 0; i < num_names; i++) {
   (*names)[i]= NULL;
   (*values)[i]= NULL;
   (*value_lengths)[i]= 0;
 }

#ifdef Libisofs_with_freebsd_extattR

 if(!(flag & 4)) { /* Get xattr values */
   for(i= 0; i < list_size && (size_t) num_names - acl_names > *num_attrs;
       i+= strlen(list + i) + 1) {
     if(!(flag & 8))
       if(strncmp(list + i, "user.", 5))
   continue;
     (*names)[(*num_attrs)++]= strdup(list + i);
     if((*names)[(*num_attrs) - 1] == NULL)
       {ret= -1; goto ex;}
   }
 
   for(i= 0; (size_t) i < *num_attrs; i++) {
     if(strncmp((*names)[i], "user.", 5) == 0) {
       attrnamespace= EXTATTR_NAMESPACE_USER;
       namept= (*names)[i] + 5;
     } else {
       if(!(flag & 8))
   continue;
       attrnamespace= EXTATTR_NAMESPACE_SYSTEM;
       namept= (*names)[i] + 7;
     }
     /* Predict length of value */
     if(flag & 32) /* follow link */
       value_ret= extattr_get_file(path, attrnamespace, namept,
                                   NULL, (size_t) 0);
     else
       value_ret= extattr_get_link(path, attrnamespace, namept,
                                   NULL, (size_t) 0);
     if(value_ret == -1)
 continue;

     (*values)[i]= calloc(value_ret + 1, 1);
     if((*values)[i] == NULL)
       {ret= -1; goto ex;}

     /* Obtain value */
     if(flag & 32) /* follow link */
       value_ret= extattr_get_file(path, attrnamespace, namept,
                                   (*values)[i], (size_t) value_ret);
     else
       value_ret= extattr_get_link(path, attrnamespace, namept,
                                   (*values)[i], (size_t) value_ret);
     if(value_ret == -1) { /* there could be a race condition */

       if(retry++ > 5)
         {ret= -1; goto ex;}
       i--;
 continue;
     }
     (*value_lengths)[i]= value_ret;
     retry= 0;
   }
 }

#endif /* Libisofs_with_freebsd_extattR */

#ifdef Libisofs_with_aaip_acL

 if(flag & 1) { /* Obtain ACL */
  /* access-ACL */
   aaip_get_acl_text(path, &a_acl_text, flag & (16 | 32));
   if(a_acl_text == NULL)
     {ret= 1; goto ex;} /* empty ACL / only st_mode info was found in ACL */
   ret= aaip_encode_acl(a_acl_text, (mode_t) 0, &a_acl_len, &a_acl, flag & 2);
   if(ret <= 0)
     goto ex;

   /* Note: There are no default-ACL in FreeBSD */

   /* Set as attribute with empty name */;
   (*names)[*num_attrs]= strdup("");
   if((*names)[*num_attrs] == NULL)
     {ret= -1; goto ex;}
   (*values)[*num_attrs]= (char *) a_acl;
   a_acl= NULL;
   (*value_lengths)[*num_attrs]= a_acl_len;
   (*num_attrs)++;
 }

#endif /* Libisofs_with_aaip_acL */

 ret= 1;
ex:;
#ifdef Libisofs_with_aaip_acL
 if(a_acl != NULL)
   free(a_acl);
 if(a_acl_text != NULL)
   aaip_get_acl_text("", &a_acl_text, 1 << 15); /* free */
#endif
#ifdef Libisofs_with_freebsd_extattR
 if(list != NULL)
   free(list);
 if(user_list != NULL)
   free(user_list);
 if(sys_list != NULL)
   free(sys_list);
#endif

 if(ret <= 0 || (flag & (1 << 15))) {
   if(*names != NULL) {
     for(i= 0; (size_t) i < *num_attrs; i++)
       free((*names)[i]);
     free(*names);
   }
   *names= NULL;
   if(*value_lengths != NULL)
     free(*value_lengths);
   *value_lengths= NULL;
   if(*values != NULL) {
     for(i= 0; (size_t) i < *num_attrs; i++)
       free((*values)[i]);
     free(*values);
   }
   *values= NULL;
   *num_attrs= 0;
 }
 return(ret);
}
Esempio n. 9
0
int get_xattr(const char *path, struct stat *statp,
	char **xattrtext, size_t *xlen, struct conf *conf)
{
	int i=0;
	size_t maxlen=0xFFFFFFFF/2;

	for(i=0; i<(int)(sizeof(namespaces)/sizeof(int)); i++)
	{
		int j=0;
		size_t len=0;
		int have_acl=0;
		char *xattrlist=NULL;
		char *cnamespace=NULL;
		size_t totallen=0;
		char *toappend=NULL;
		char ctuple[BSD_BUF_SIZE]="";
		char cattrname[BSD_BUF_SIZE]="";
		if((len=extattr_list_link(path, namespaces[i], NULL, 0))<0)
		{
			logw(conf, "could not extattr_list_link of '%s': %d\n",
				path, len);
			return 0; // carry on
		}
		if(!len) continue;
		if(xattrtext && *xattrtext)
		{
			// Already have some meta text, which means that some
			// ACLs were set.
			have_acl++;
		}
		if(!(xattrlist=(char *)malloc(len+1)))
		{
			log_out_of_memory(__func__);
			return -1;
		}
		memset(xattrlist, 0, len+1);
		if((len=extattr_list_link(path, namespaces[i], xattrlist, len))<=0)
		{
			logw(conf, "could not extattr_list_link '%s': %d\n",
				path, len);
			free(xattrlist);
			return 0; // carry on
		}
		xattrlist[len]='\0';

		// Convert namespace number to string. It has to be freed
		// later on.
		if(extattr_namespace_to_string(namespaces[i], &cnamespace))
		{
			logp("Failed to convert %d into namespace on '%s'\n",
				 namespaces[i], path);
			free(xattrlist);
			return 0; // carry on
		}


		for(j=0; j<(int)len; j+=xattrlist[j]+1)
		{
			int cnt=0;
			char tmp1[9];
			char tmp2[9];
			size_t zlen=0;
			size_t vlen=0;
			char *val=NULL;
			cnt=xattrlist[j];
			if(cnt>((int)sizeof(cattrname)-1))
				cnt=((int)sizeof(cattrname)-1);
			strncpy(cattrname, xattrlist+(j+1), cnt);
			cattrname[cnt]='\0';
			snprintf(ctuple, sizeof(ctuple), "%s.%s",
				cnamespace, cattrname);

			if(have_acl)
			{
				int c=0;
				int skip=0;
				// skip xattr entries that were already saved
				// as ACLs.
				for(c=0; acl_skiplist[c]; c++)
				{
					if(!strcmp(ctuple, acl_skiplist[c]))
					{
						skip++;
						break;
					}
				}
				if(skip) continue;
			}
			zlen=strlen(ctuple);
			//printf("\ngot: %s (%s)\n", ctuple, path);

			if((vlen=extattr_list_link(path, namespaces[i],
				xattrlist, len))<0)
			{
				logw(conf, "could not extattr_list_link on %s for %s: %d\n", path, namespaces[i], vlen);
				continue;
			}
			if(!(val=(char *)malloc(vlen+1)))
			{
				log_out_of_memory(__func__);
				free(xattrlist);
				if(toappend) free(toappend);
				return -1;
			}
			if((vlen=extattr_get_link(path, namespaces[i],
				cattrname, val, vlen))<0)
			{
				logw(conf, "could not extattr_list_link %s for %s: %d\n", path, namespaces[i], vlen);
				free(val);
				continue;
			}
			val[vlen]='\0';

			if(vlen>maxlen)
			{
				logw(conf, "xattr value of '%s' too long: %d\n",
					path, vlen);
				if(toappend) { free(toappend); toappend=NULL; }
				free(val);
				break;
			}

			snprintf(tmp1, sizeof(tmp1), "%08X", (unsigned)zlen);
			snprintf(tmp2, sizeof(tmp2), "%08X", (unsigned)vlen);
			if(!(toappend=prepend_len(toappend, totallen,
				tmp1, 8, "", 0, &totallen))
			  || !(toappend=prepend_len(toappend, totallen,
				ctuple, zlen, "", 0, &totallen))
			  || !(toappend=prepend_len(toappend, totallen,
				tmp2, 8, "", 0, &totallen))
			  || !(toappend=prepend_len(toappend, totallen,
				val, vlen, "", 0, &totallen)))
			{
				log_out_of_memory(__func__);
				free(val);
				free(xattrlist);
				return -1;
			}
			free(val);

			if(totallen>maxlen)
			{
				logw(conf, "xattr length of '%s' grew too long: %d\n",
					path, totallen);
				free(val);
				free(toappend);
				free(xattrlist);
				return 0; // carry on
			}

			//printf("now: %s\n", toappend);
		}

		free(cnamespace);

		if(toappend)
		{
			char tmp3[10];
			snprintf(tmp3, sizeof(tmp3), "%c%08X",
				META_XATTR_BSD, (unsigned)totallen);
			if(!(*xattrtext=prepend_len(*xattrtext, *xlen,
				tmp3, 9, "", 0, xlen))
			  || !(*xattrtext=prepend_len(*xattrtext, *xlen,
				toappend, totallen, "", 0, xlen)))
			{
				log_out_of_memory(__func__);
				free(toappend);
				free(xattrlist);
				return -1;
			}
			free(toappend);
			//printf("and: %s %li\n", *xattrtext, *xlen);
		}
		free(xattrlist);
	}

	return 0;
}