diff -r dc4f96f3d329 Lib/test/test_os.py --- a/Lib/test/test_os.py Thu Apr 16 20:26:19 2015 +0200 +++ b/Lib/test/test_os.py Fri Apr 17 19:37:51 2015 -0700 @@ -2376,10 +2376,14 @@ def _check_xattrs_str(self, s, getxattr, setxattr, removexattr, listxattr, **kwargs): fn = support.TESTFN + if sys.platform.startswith("freebsd"): + xattr_errno = errno.ENOATTR + else: + xattr_errno = errno.ENODATA open(fn, "wb").close() with self.assertRaises(OSError) as cm: getxattr(fn, s("user.test"), **kwargs) - self.assertEqual(cm.exception.errno, errno.ENODATA) + self.assertEqual(cm.exception.errno, xattr_errno) init_xattr = listxattr(fn) self.assertIsInstance(init_xattr, list) setxattr(fn, s("user.test"), b"", **kwargs) @@ -2394,14 +2398,14 @@ self.assertEqual(cm.exception.errno, errno.EEXIST) with self.assertRaises(OSError) as cm: setxattr(fn, s("user.test2"), b"bye", os.XATTR_REPLACE, **kwargs) - self.assertEqual(cm.exception.errno, errno.ENODATA) + self.assertEqual(cm.exception.errno, xattr_errno) setxattr(fn, s("user.test2"), b"foo", os.XATTR_CREATE, **kwargs) xattr.add("user.test2") self.assertEqual(set(listxattr(fn)), xattr) removexattr(fn, s("user.test"), **kwargs) with self.assertRaises(OSError) as cm: getxattr(fn, s("user.test"), **kwargs) - self.assertEqual(cm.exception.errno, errno.ENODATA) + self.assertEqual(cm.exception.errno, xattr_errno) xattr.remove("user.test") self.assertEqual(set(listxattr(fn)), xattr) self.assertEqual(getxattr(fn, s("user.test2"), **kwargs), b"foo") diff -r dc4f96f3d329 Modules/posixmodule.c --- a/Modules/posixmodule.c Thu Apr 16 20:26:19 2015 +0200 +++ b/Modules/posixmodule.c Fri Apr 17 19:37:51 2015 -0700 @@ -95,12 +95,327 @@ #undef HAVE_SCHED_SETAFFINITY #endif -#if defined(HAVE_SYS_XATTR_H) && defined(__GLIBC__) && !defined(__FreeBSD_kernel__) && !defined(__GNU__) +#if defined(HAVE_SYS_XATTR_H) && defined(__GLIBC__) && !defined(__GNU__) #define USE_XATTRS -#endif - -#ifdef USE_XATTRS +#elif defined(HAVE_SYS_EXTATTR_H) && defined(__FreeBSD__) +#define USE_XATTRS +#endif + +#if defined(USE_XATTRS) && defined(HAVE_SYS_XATTR_H) #include +#elif defined(USE_XATTRS) && defined(HAVE_SYS_EXTATTR_H) +#include +#define XATTR_SIZE_MAX NAME_MAX +#define XATTR_LIST_MAX 1024 +#define XATTR_CREATE 0 +#define XATTR_REPLACE 0 +#endif + +#if defined(USE_XATTRS) && defined(__FreeBSD__) + +/* Turns a qualified string into a namespace id on FreeBSD. + * This ensures that that the namespace is qualified + * ((user|system).) and that is non-null. + */ +static int +xattrnamespace(int *namespace, const char *fullattr) +{ + char *sep = strchr(fullattr, '.'); + size_t nslen = 0; + int ret = 0; + + *namespace = -1; + // return ENOATTR on unqualified names + if (sep == NULL || *(sep + 1) == '\0') + return ENOATTR; + + if (sep < fullattr) + return ENOATTR; + + nslen = sep - fullattr + 1; + + if (strncmp(fullattr, "user", (4 < nslen ? 4 : nslen)) == 0) { + *namespace = EXTATTR_NAMESPACE_USER; + } else if (strncmp(fullattr, "system", (6 < nslen ? 6 : nslen)) == 0) { + *namespace = EXTATTR_NAMESPACE_SYSTEM; + } + + if (*namespace == -1) + ret = ENOATTR; + + return ret; +} + +static ssize_t +getxattr(const char *path, const char *name, void *value, size_t size) +{ + int nsid = 0; + int err = 0; + char *attr_name = NULL; + + if ((err = xattrnamespace(&nsid, name))) { + errno = err; + return -1; + } + + attr_name = strchr(name, '.') + 1; + + return extattr_get_file(path, nsid, attr_name, value, size); +} + +static ssize_t +lgetxattr(const char *path, const char *name, void *value, size_t size) +{ + int nsid = 0; + int err = 0; + char *attr_name = NULL; + + if ((err = xattrnamespace(&nsid, name))) { + errno = err; + return -1; + } + + attr_name = strchr(name, '.') + 1; + + return extattr_get_link(path, nsid, attr_name, value, size); +} + +static ssize_t +fgetxattr(int fd, const char *name, void *value, size_t size) +{ + int nsid = 0; + int err = 0; + char *attr_name = NULL; + + if ((err = xattrnamespace(&nsid, name))) { + errno = err; + return -1; + } + + attr_name = strchr(name, '.') + 1; + + return extattr_get_fd(fd, nsid, attr_name, value, size); +} + +static int +setxattr(const char *path, const char *name, const void *value, size_t size, int flags) +{ + int nsid = 0; + int err = 0; + char *attr_name = NULL; + + if ((err = xattrnamespace(&nsid, name))) { + errno = err; + return -1; + } + + attr_name = strchr(name, '.') + 1; + + if (extattr_set_file(path, nsid, attr_name, value, size) != -1) + return 0; + return -1; +} + +static int +lsetxattr(const char *path, const char *name, const void *value, size_t size, int flags) +{ + int nsid = 0; + int err = 0; + char *attr_name = NULL; + + if ((err = xattrnamespace(&nsid, name))) { + errno = err; + return -1; + } + + attr_name = strchr(name, '.') + 1; + + if (extattr_set_link(path, nsid, attr_name, value, size) != -1) + return 0; + return -1; +} + +static int +fsetxattr(int fd, const char *name, const void *value, size_t size, int flags) +{ + int nsid = 0; + int err = 0; + char *attr_name = NULL; + + if ((err = xattrnamespace(&nsid, name))) { + errno = err; + return -1; + } + + attr_name = strchr(name, '.') + 1; + + if (extattr_set_fd(fd, nsid, attr_name, value, size) != -1) + return 0; + return -1; +} + +static int +removexattr(const char *path, const char *name) +{ + int nsid = 0; + int err = 0; + char *attr_name = NULL; + + if ((err = xattrnamespace(&nsid, name))) { + errno = err; + return -1; + } + + attr_name = strchr(name, '.') + 1; + + return extattr_delete_file(path, nsid, attr_name); +} + +static int +lremovexattr(const char *path, const char *name) +{ + int nsid = 0; + int err = 0; + char *attr_name = NULL; + + if ((err = xattrnamespace(&nsid, name))) { + errno = err; + return -1; + } + + attr_name = strchr(name, '.') + 1; + + return extattr_delete_link(path, nsid, attr_name); +} + +static int +fremovexattr(int fd, const char *name) +{ + int nsid = 0; + int err = 0; + char *attr_name = NULL; + + if ((err = xattrnamespace(&nsid, name))) { + errno = err; + return -1; + } + + attr_name = strchr(name, '.') + 1; + + return extattr_delete_fd(fd, nsid, attr_name); +} + +static ssize_t +listxattr(const char *path, char *list, size_t size) +{ + ssize_t ret = 0, retaddr = 0; + int i; + + retaddr = extattr_list_file(path, EXTATTR_NAMESPACE_SYSTEM, list, size); + if (retaddr == -1 && errno != EPERM) { + return retaddr; + } else { + ret += (retaddr == -1 ? 0 : retaddr); + } + + retaddr = extattr_list_file(path, EXTATTR_NAMESPACE_USER, list + ret, size - retaddr); + if (retaddr == -1) { + return retaddr; + } else { + ret += retaddr; + } + + // empty + if (ret < 2) { + return 0; + } + + for (i = 0; i < ret; i++) { + if (! isalpha(list[i])) { + list[i] = '\0'; + } + } + + memmove(list, list + 1, ret); + list[ret - 1] = '\0'; + + return ret; +} + +static ssize_t +llistxattr(const char *path, char *list, size_t size) +{ + ssize_t ret = 0, retaddr = 0; + int i; + + retaddr = extattr_list_link(path, EXTATTR_NAMESPACE_SYSTEM, list, size); + if (retaddr == -1 && errno != EPERM) { + return retaddr; + } else { + ret += (retaddr == -1 ? 0 : retaddr); + } + + retaddr = extattr_list_link(path, EXTATTR_NAMESPACE_USER, list + ret, size - retaddr); + if (retaddr == -1) { + return retaddr; + } else { + ret += retaddr; + } + + // empty + if (ret < 2) { + return 0; + } + + for (i = 0; i < ret; i++) { + if (! isalpha(list[i])) { + list[i] = '\0'; + } + } + + memmove(list, list + 1, ret); + list[ret - 1] = '\0'; + + return ret; +} + +static ssize_t +flistxattr(int fd, char *list, size_t size) +{ + ssize_t ret = 0, retaddr = 0; + int i; + + retaddr = extattr_list_fd(fd, EXTATTR_NAMESPACE_SYSTEM, list, size); + if (retaddr == -1 && errno != EPERM) { + return retaddr; + } else { + ret += (retaddr == -1 ? 0 : retaddr); + } + + retaddr = extattr_list_fd(fd, EXTATTR_NAMESPACE_USER, list + ret, size - retaddr); + if (retaddr == -1) { + return retaddr; + } else { + ret += retaddr; + } + + // empty + if (ret < 2) { + return 0; + } + + for (i = 0; i < ret; i++) { + if (! isalnum(list[i])) { + list[i] = '\0'; + } + } + + memmove(list, list + 1, ret); + list[ret - 1] = '\0'; + + return ret; +} + #endif #if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__APPLE__) diff -r dc4f96f3d329 configure --- a/configure Thu Apr 16 20:26:19 2015 +0200 +++ b/configure Fri Apr 17 19:37:51 2015 -0700 @@ -7275,7 +7275,7 @@ sys/times.h sys/types.h sys/uio.h sys/un.h sys/utsname.h sys/wait.h pty.h \ libutil.h sys/resource.h netpacket/packet.h sysexits.h bluetooth.h \ bluetooth/bluetooth.h linux/tipc.h spawn.h util.h alloca.h endian.h \ -sys/endian.h +sys/endian.h sys/extattr.h do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" diff -r dc4f96f3d329 configure.ac --- a/configure.ac Thu Apr 16 20:26:19 2015 +0200 +++ b/configure.ac Fri Apr 17 19:37:51 2015 -0700 @@ -1750,7 +1750,7 @@ sys/times.h sys/types.h sys/uio.h sys/un.h sys/utsname.h sys/wait.h pty.h \ libutil.h sys/resource.h netpacket/packet.h sysexits.h bluetooth.h \ bluetooth/bluetooth.h linux/tipc.h spawn.h util.h alloca.h endian.h \ -sys/endian.h) +sys/endian.h sys/extattr.h) AC_HEADER_DIRENT AC_HEADER_MAJOR diff -r dc4f96f3d329 pyconfig.h.in --- a/pyconfig.h.in Thu Apr 16 20:26:19 2015 +0200 +++ b/pyconfig.h.in Fri Apr 17 19:37:51 2015 -0700 @@ -972,6 +972,9 @@ /* Define to 1 if you have the header file. */ #undef HAVE_SYS_EVENT_H +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_EXTATTR_H + /* Define to 1 if you have the header file. */ #undef HAVE_SYS_FILE_H