++#elif HAVE_FREEBSD_XATTRS
++
++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);
++}
++
++ssize_t sys_fgetxattr(int filedes, const char *name, void *value, size_t size)
++{
++ return extattr_get_fd(filedes, EXTATTR_NAMESPACE_USER, name, value, size);
++}
++
++int sys_lsetxattr(const char *path, const char *name, const void *value, size_t size)
++{
++ return extattr_set_link(path, EXTATTR_NAMESPACE_USER, name, value, size);
++}
++
++int sys_lremovexattr(const char *path, const char *name)
++{
++ return extattr_delete_link(path, EXTATTR_NAMESPACE_USER, name);
++}
++
++ssize_t sys_llistxattr(const char *path, char *list, size_t size)
++{
++ unsigned char keylen;
++ ssize_t off, len = extattr_list_link(path, EXTATTR_NAMESPACE_USER, list, size);
++
++ if (len <= 0 || (size_t)len > size)
++ return len;
++
++ /* FreeBSD puts a single-byte length before each string, with no '\0'
++ * terminator. We need to change this into a series of null-terminted
++ * strings. Since the size is the same, we can simply transform the
++ * output in place. */
++ for (off = 0; off < len; off += keylen + 1) {
++ keylen = ((unsigned char*)list)[off];
++ if (off + keylen >= len) {
++ /* Should be impossible, but kernel bugs happen! */
++ errno = EINVAL;
++ return -1;
++ }
++ memmove(list+off, list+off+1, keylen);
++ list[off+keylen] = '\0';
++ }
++
++ return len;
++}
++