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 }
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 }
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; }
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); } }
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); }
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); }
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; }
/* 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); }
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; }