aboutsummaryrefslogtreecommitdiffstats
path: root/ports
diff options
context:
space:
mode:
authorSeebs <seebs@seebs.net>2014-07-10 15:38:06 -0500
committerSeebs <seebs@seebs.net>2014-07-10 16:20:13 -0500
commit97511c878d455805759caa7146906f552c49eb06 (patch)
tree569930d47e0faa3a61f27e596e1973642168d102 /ports
parent093516338afdf7a29889c9a2ce46facb8eef0e3f (diff)
downloadpseudo-97511c878d455805759caa7146906f552c49eb06.tar.gz
pseudo-97511c878d455805759caa7146906f552c49eb06.tar.bz2
pseudo-97511c878d455805759caa7146906f552c49eb06.zip
make xattr work on Darwin
More complicated, because we actually need to make com.apple stuff work probably.
Diffstat (limited to 'ports')
-rw-r--r--ports/darwin/guts/fgetxattr.c4
-rw-r--r--ports/darwin/guts/flistxattr.c4
-rw-r--r--ports/darwin/guts/fremovexattr.c13
-rw-r--r--ports/darwin/guts/fsetxattr.c4
-rw-r--r--ports/darwin/guts/getxattr.c6
-rw-r--r--ports/darwin/guts/listxattr.c6
-rw-r--r--ports/darwin/guts/removexattr.c13
-rw-r--r--ports/darwin/guts/setxattr.c6
-rw-r--r--ports/darwin/pseudo_wrappers.c321
-rw-r--r--ports/darwin/wrapfuncs.in17
-rw-r--r--ports/linux/xattr/pseudo_wrappers.c2
11 files changed, 356 insertions, 40 deletions
diff --git a/ports/darwin/guts/fgetxattr.c b/ports/darwin/guts/fgetxattr.c
index 1cd8904..dbb3681 100644
--- a/ports/darwin/guts/fgetxattr.c
+++ b/ports/darwin/guts/fgetxattr.c
@@ -1,12 +1,12 @@
/*
- * Copyright (c) 2011 Wind River Systems; see
+ * Copyright (c) 2014 Wind River Systems; see
* guts/COPYRIGHT for information.
*
* ssize_t fgetxattr(int filedes, const char *name, void *value, size_t size, u_int32_t position, int options)
* ssize_t rc = -1;
*/
- rc = real_fgetxattr(filedes, name, value, size, position, options);
+ rc = shared_getxattr(NULL, filedes, name, value, size, position, options);
/* return rc;
* }
diff --git a/ports/darwin/guts/flistxattr.c b/ports/darwin/guts/flistxattr.c
index 7575f28..bfaa4e9 100644
--- a/ports/darwin/guts/flistxattr.c
+++ b/ports/darwin/guts/flistxattr.c
@@ -1,12 +1,12 @@
/*
- * Copyright (c) 2011 Wind River Systems; see
+ * Copyright (c) 2014 Wind River Systems; see
* guts/COPYRIGHT for information.
*
* ssize_t flistxattr(int filedes, char *list, size_t size, int options)
* ssize_t rc = -1;
*/
- rc = real_flistxattr(filedes, list, size, options);
+ rc = shared_listxattr(NULL, filedes, list, size, options);
/* return rc;
* }
diff --git a/ports/darwin/guts/fremovexattr.c b/ports/darwin/guts/fremovexattr.c
new file mode 100644
index 0000000..4edc38c
--- /dev/null
+++ b/ports/darwin/guts/fremovexattr.c
@@ -0,0 +1,13 @@
+/*
+ * Copyright (c) 2014 Wind River Systems; see
+ * guts/COPYRIGHT for information.
+ *
+ * int fremovexattr(int filedes, const char *name, int options)
+ * int rc = -1;
+ */
+
+ rc = shared_removexattr(NULL, filedes, name, options);
+
+/* return rc;
+ * }
+ */
diff --git a/ports/darwin/guts/fsetxattr.c b/ports/darwin/guts/fsetxattr.c
index 541569a..d707595 100644
--- a/ports/darwin/guts/fsetxattr.c
+++ b/ports/darwin/guts/fsetxattr.c
@@ -1,12 +1,12 @@
/*
- * Copyright (c) 2011 Wind River Systems; see
+ * Copyright (c) 2014 Wind River Systems; see
* guts/COPYRIGHT for information.
*
* int fsetxattr(int filedes, const char *name, const void *value, size_t size, u_int32_t position, int options)
* int rc = -1;
*/
- rc = real_fsetxattr(filedes, name, value, size, position, options);
+ rc = shared_setxattr(NULL, filedes, name, value, size, position, options);
/* return rc;
* }
diff --git a/ports/darwin/guts/getxattr.c b/ports/darwin/guts/getxattr.c
index 16f0993..ecef9cf 100644
--- a/ports/darwin/guts/getxattr.c
+++ b/ports/darwin/guts/getxattr.c
@@ -1,12 +1,12 @@
/*
- * Copyright (c) 2011 Wind River Systems; see
+ * Copyright (c) 2014 Wind River Systems; see
* guts/COPYRIGHT for information.
*
- * ssize_t getxattr(const char *pathname, const char *name, void *value, size_t size, u_int32_t position, int options)
+ * ssize_t getxattr(const char *path, const char *name, void *value, size_t size, u_int32_t position, int options)
* ssize_t rc = -1;
*/
- rc = real_getxattr(pathname, name, value, size, position, options);
+ rc = shared_getxattr(path, -1, name, value, size, position, options);
/* return rc;
* }
diff --git a/ports/darwin/guts/listxattr.c b/ports/darwin/guts/listxattr.c
index 0bba451..5a8a7a8 100644
--- a/ports/darwin/guts/listxattr.c
+++ b/ports/darwin/guts/listxattr.c
@@ -1,12 +1,12 @@
/*
- * Copyright (c) 2011 Wind River Systems; see
+ * Copyright (c) 2014 Wind River Systems; see
* guts/COPYRIGHT for information.
*
- * ssize_t listxattr(const char *pathname, char *list, size_t size, int options)
+ * ssize_t listxattr(const char *path, char *list, size_t size, int options)
* ssize_t rc = -1;
*/
- rc = real_listxattr(pathname, list, size, options);
+ rc = shared_listxattr(path, -1, list, size, options);
/* return rc;
* }
diff --git a/ports/darwin/guts/removexattr.c b/ports/darwin/guts/removexattr.c
new file mode 100644
index 0000000..c125b1a
--- /dev/null
+++ b/ports/darwin/guts/removexattr.c
@@ -0,0 +1,13 @@
+/*
+ * Copyright (c) 2014 Wind River Systems; see
+ * guts/COPYRIGHT for information.
+ *
+ * int removexattr(const char *path, const char *name, int options)
+ * int rc = -1;
+ */
+
+ rc = shared_removexattr(path, -1, name, options);
+
+/* return rc;
+ * }
+ */
diff --git a/ports/darwin/guts/setxattr.c b/ports/darwin/guts/setxattr.c
index 3c8fd3d..10ffba4 100644
--- a/ports/darwin/guts/setxattr.c
+++ b/ports/darwin/guts/setxattr.c
@@ -1,12 +1,12 @@
/*
- * Copyright (c) 2011 Wind River Systems; see
+ * Copyright (c) 2014 Wind River Systems; see
* guts/COPYRIGHT for information.
*
- * int setxattr(const char *pathname, const char *name, const void *value, size_t size, u_int32_t position, int options)
+ * int setxattr(const char *path, const char *name, const void *value, size_t size, u_int32_t position, int options)
* int rc = -1;
*/
- rc = real_setxattr(pathname, name, value, size, position, options);
+ rc = shared_setxattr(path, -1, name, value, size, position, options);
/* return rc;
* }
diff --git a/ports/darwin/pseudo_wrappers.c b/ports/darwin/pseudo_wrappers.c
index 36d9172..8a0222f 100644
--- a/ports/darwin/pseudo_wrappers.c
+++ b/ports/darwin/pseudo_wrappers.c
@@ -17,31 +17,295 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
-/* there's no fgetgrent_r or fgetpwent_r in Darwin */
-int
-pseudo_getpwent_r(struct passwd *pwbuf, char *buf, size_t buflen, struct passwd **pwbufp) {
- /* note that we don't wrap fgetpwent_r, since there's no path
- * references in it.
- */
- if (!pseudo_pwd) {
- errno = ENOENT;
+/* we need XATTR_NOFOLLOW in scope */
+#include <sys/xattr.h>
+
+/* shared functionality for the xattr code */
+/* Each of these functions is expecting to get an optional name, and
+ * a populated statbuf to use for sending messages to the server.
+ */
+
+/* to avoid namespace pollution and such, we now duplicate the
+ * basic functionality of a POSIX ACL list, as used by libacl or
+ * the kernel. Documentation was obtained from the headers of libacl
+ * and from a page or two of _The Linux Programming Interface_, by
+ * Michael Kerrisk.
+ */
+
+typedef struct {
+ uint16_t tag;
+ uint16_t perm;
+ uint32_t id;
+} acl_entry;
+
+typedef struct {
+ uint32_t version;
+ acl_entry entries[];
+} acl_header;
+
+enum acl_tags {
+ ACL_UNDEFINED = 0x0,
+ ACL_USER_OBJ = 0x1,
+ ACL_USER = 0x2,
+ ACL_GROUP_OBJ = 0x4,
+ ACL_GROUP = 0x8,
+ ACL_MASK = 0x10,
+ ACL_OTHER = 0x20,
+};
+
+static const int endian_test = 1;
+static const char *endian_tester = (char *) &endian_test;
+
+static inline int
+le16(int x16) {
+ if (*endian_tester) {
+ return x16;
+ } else {
+ return ((x16 & 0xff) << 8) | ((x16 & 0xff00) >> 8);
+ }
+}
+
+static inline int
+le32(int x32) {
+ if (*endian_tester) {
+ return x32;
+ } else {
+ return ((x32 & 0xff) << 24) | ((x32 & 0xff00) << 8) |
+ ((x32 & 0xff0000) >> 8) | ((x32 & 0xff000000) >> 24);
+ }
+}
+
+/* set mode to match the contents of header. Return non-zero on error.
+ * On a zero return, mode is a valid posix mode, and *extra is set to
+ * 1 if any of the entries are not reflected by that mode. On a non-zero
+ * return, no promises are made about *extra or *mode.
+ */
+static int
+posix_permissions(const acl_header *header, int entries, int *extra, int *mode) {
+ int acl_seen = 0;
+ if (le32(header->version) != 2) {
+ pseudo_diag("Fatal: ACL support no available for header version %d.\n",
+ le32(header->version));
+ return 1;
+ }
+ *mode = 0;
+ *extra = 0;
+ for (int i = 0; i < entries; ++i) {
+ const acl_entry *e = &header->entries[i];
+ int tag = le16(e->tag);
+ int perm = le16(e->perm);
+ acl_seen |= tag;
+ switch (tag) {
+ case ACL_USER_OBJ:
+ *mode = *mode | (perm << 6);
+ break;
+ case ACL_GROUP_OBJ:
+ *mode = *mode | (perm << 3);
+ break;
+ case ACL_OTHER:
+ *mode = *mode | perm;
+ break;
+ case ACL_USER:
+ case ACL_GROUP:
+ case ACL_MASK:
+ *extra = *extra + 1;
+ break;
+ default:
+ pseudo_debug(PDBGF_XATTR, "Unknown tag in ACL: 0x%x.\n",
+ tag);
+ return 1;
+ }
+ }
+ return 0;
+}
+
+#define RC_AND_BUF \
+ int rc; \
+ PSEUDO_STATBUF buf; \
+ if (path) { \
+ rc = base_lstat(path, &buf); \
+ } else { \
+ rc = base_fstat(fd, &buf); \
+ } \
+ if (rc == -1) { \
+ return rc; \
+ }
+
+static ssize_t shared_getxattr(const char *path, int fd, const char *name, void *value, size_t size, u_int32_t position, int options) {
+ RC_AND_BUF
+
+ if (!strncmp(name, "com.apple.", 10)) {
+ if (fd != -1) {
+ return real_fgetxattr(fd, name, value, size, position, options);
+ } else {
+ return real_getxattr(path, name, value, size, position, options);
+ }
+ }
+
+ pseudo_debug(PDBGF_XATTR, "getxattr(%s [fd %d], %s)\n",
+ path ? path : "<no path>", fd, name);
+ pseudo_msg_t *result = pseudo_client_op(OP_GET_XATTR, 0, fd, -1, path, &buf, name);
+ if (result->result != RESULT_SUCCEED) {
+ errno = ENOATTR;
return -1;
}
- return fgetpwent_r(pseudo_pwd, pwbuf, buf, buflen, pwbufp);
+
+ if (value) {
+ pseudo_debug(PDBGF_XATTR, "returned attributes: '%s' (%d bytes)\n",
+ result->path, result->pathlen);
+ if (size >= result->pathlen) {
+ memcpy(value, result->path, result->pathlen);
+ } else {
+ memcpy(value, result->path, size);
+ errno = ERANGE;
+ }
+ }
+ return result->pathlen;
}
-int
-pseudo_getgrent_r(struct group *gbuf, char *buf, size_t buflen, struct group **gbufp) {
- /* note that we don't wrap fgetgrent_r, since there's no path
- * references in it.
- */
- if (!pseudo_grp) {
+static int shared_setxattr(const char *path, int fd, const char *name, const void *value, size_t size, u_int32_t position, int options) {
+ RC_AND_BUF
+ pseudo_op_t op;
+
+ pseudo_debug(PDBGF_XATTR, "setxattr(%s [fd %d], %s => '%.*s')\n",
+ path ? path : "<no path>", fd, name, (int) size, (char *) value);
+
+ if (!strncmp(name, "com.apple.", 10)) {
+ if (fd != -1) {
+ return real_fsetxattr(fd, name, value, size, position, options);
+ } else {
+ return real_setxattr(path, name, value, size, position, options);
+ }
+ }
+
+ /* this may be a plain chmod */
+ if (!strcmp(name, "system.posix_acl_access")) {
+ int extra;
+ int mode;
+ int entries = (size - sizeof(acl_header)) / sizeof(acl_entry);
+ if (!posix_permissions(value, entries, &extra, &mode)) {
+ pseudo_debug(PDBGF_XATTR, "posix_acl_access translated to mode %04o. Remaining attribute(s): %d.\n",
+ mode, extra);
+ buf.st_mode = mode;
+ /* we want to actually issue a corresponding chmod,
+ * as well, or else the file ends up 0600 on the
+ * host. Using the slightly-less-efficient wrap_chmod
+ * avoids possible misalignment.
+ */
+ if (path) {
+ wrap_chmod(path, mode);
+ } else {
+ wrap_fchmod(fd, mode);
+ }
+ /* we are sneaky, and do not actually record this using
+ * extended attributes. */
+ if (!extra) {
+ return 0;
+ }
+ }
+ }
+
+ if (options & XATTR_CREATE) {
+ op = OP_CREATE_XATTR;
+ } else if (options & XATTR_REPLACE) {
+ op = OP_REPLACE_XATTR;
+ } else {
+ op = OP_SET_XATTR;
+ }
+
+ pseudo_msg_t *result = pseudo_client_op(op, 0, fd, -1, path, &buf, name, value, size);
+
+ /* we automatically assume success */
+ if (op == OP_SET_XATTR) {
+ return 0;
+ }
+
+ /* CREATE/REPLACE operations can report failure */
+ if (!result || result->result == RESULT_FAIL) {
+ return -1;
+ }
+
+ return 0;
+}
+
+static ssize_t shared_listxattr(const char *path, int fd, char *list, size_t size, int options) {
+ RC_AND_BUF
+ char extra_name_buf[4096];
+ ssize_t real_attr_len;
+ ssize_t used = 0;
+ if (fd != -1) {
+ real_attr_len = real_flistxattr(fd, extra_name_buf, sizeof(extra_name_buf), options);
+ } else {
+ real_attr_len = real_listxattr(path, extra_name_buf, sizeof(extra_name_buf), options);
+ }
+ pseudo_debug(PDBGF_XATTR, "listxattr: %d bytes of FS xattr names, starting '%.*s'\n",
+ (int) real_attr_len, (int) real_attr_len, extra_name_buf);
+
+ /* we don't care why there aren't any */
+ if (real_attr_len < 1) {
+ real_attr_len = 0;
+ }
+
+ pseudo_msg_t *result = pseudo_client_op(OP_LIST_XATTR, 0, fd, -1, path, &buf);
+
+ if (result->result != RESULT_SUCCEED && real_attr_len < 1) {
+ pseudo_debug(PDBGF_XATTR, "listxattr: no success.\n");
+ errno = ENOATTR;
+ return -1;
+ }
+
+ if (list) {
+ pseudo_debug(PDBGF_XATTR, "listxattr: %d bytes of names, starting '%.*s'\n",
+ (int) result->pathlen, (int) result->pathlen, result->path);
+ if (size >= result->pathlen) {
+ memcpy(list, result->path, result->pathlen);
+ used = result->pathlen;
+ } else {
+ memcpy(list, result->path, size);
+ used = size;
+ errno = ERANGE;
+ }
+ if (real_attr_len > 0) {
+ if ((ssize_t) size >= used + real_attr_len) {
+ memcpy(list + used, extra_name_buf, real_attr_len);
+ used += real_attr_len;
+ } else {
+ memcpy(list + used, extra_name_buf, size - used);
+ used = size;
+ errno = ERANGE;
+ }
+
+ }
+ } else {
+ used = real_attr_len + result->pathlen;
+ }
+ return used;
+}
+
+static int shared_removexattr(const char *path, int fd, const char *name, int options) {
+ RC_AND_BUF
+
+ if (!strncmp(name, "com.apple.", 10)) {
+ if (fd != -1) {
+ return real_fremovexattr(fd, name, options);
+ } else {
+ return real_removexattr(path, name, options);
+ }
+ }
+
+ pseudo_msg_t *result = pseudo_client_op(OP_REMOVE_XATTR, 0, fd, -1, path, &buf, name);
+
+ if (result->result != RESULT_SUCCEED) {
+ /* docs say ENOATTR, but I don't have one */
errno = ENOENT;
return -1;
}
- return fgetgrent_r(pseudo_grp, gbuf, buf, buflen, gbufp);
+ return 0;
}
+
+/* there's no fgetgrent_r or fgetpwent_r in Darwin */
+
#define PLENTY_LONG 2048
/* the original uid/gid code for Linux was written in terms of the
* fget*ent_r() functions... which Darwin doesn't have. But wait! They're
@@ -314,3 +578,28 @@ error_out:
return error;
return -1;
}
+
+int
+pseudo_getpwent_r(struct passwd *pwbuf, char *buf, size_t buflen, struct passwd **pwbufp) {
+ /* note that we don't wrap fgetpwent_r, since there's no path
+ * references in it.
+ */
+ if (!pseudo_pwd) {
+ errno = ENOENT;
+ return -1;
+ }
+ return pseudo_fgetpwent_r(pseudo_pwd, pwbuf, buf, buflen, pwbufp);
+}
+
+int
+pseudo_getgrent_r(struct group *gbuf, char *buf, size_t buflen, struct group **gbufp) {
+ /* note that we don't wrap fgetgrent_r, since there's no path
+ * references in it.
+ */
+ if (!pseudo_grp) {
+ errno = ENOENT;
+ return -1;
+ }
+ return pseudo_fgetgrent_r(pseudo_grp, gbuf, buf, buflen, gbufp);
+}
+
diff --git a/ports/darwin/wrapfuncs.in b/ports/darwin/wrapfuncs.in
index c1c00b7..306ad66 100644
--- a/ports/darwin/wrapfuncs.in
+++ b/ports/darwin/wrapfuncs.in
@@ -7,14 +7,6 @@ int fcntl(int fd, int cmd, ...{struct flock *lock});
# just so we know the inums of symlinks
# for emulation of passwd utilities
int getgrouplist(const char *user, gid_t group, gid_t *groups, int *ngroups);
-# we use "pathname" to avoid canonicalizing paths, because these functions are
-# unimplemented
-ssize_t getxattr(const char *pathname, const char *name, void *value, size_t size, u_int32_t position, int options);
-ssize_t fgetxattr(int filedes, const char *name, void *value, size_t size, u_int32_t position, int options);
-ssize_t listxattr(const char *pathname, char *list, size_t size, int options);
-ssize_t flistxattr(int filedes, char *list, size_t size, int options);
-int setxattr(const char *pathname, const char *name, const void *value, size_t size, u_int32_t position, int options);
-int fsetxattr(int filedes, const char *name, const void *value, size_t size, u_int32_t position, int options);
# local color UIDs
int getgrouplist(const char *name, int basegid, int *groups, int *ngroups);
int scandir(const char *path, struct dirent ***namelist, int (*filter)(const struct dirent *), int (*compar)());
@@ -24,3 +16,12 @@ int fgetpwent_r(FILE *fp, struct passwd *pbuf, char *buf, size_t buflen, struct
int getpwent_r(struct passwd *pwbuf, char *buf, size_t buflen, struct passwd **pwbufp); /* real_func=pseudo_getpwent_r */
int getgrent_r(struct group *gbuf, char *buf, size_t buflen, struct group **gbufp); /* real_func=pseudo_getgrent_r */
int sync_file_range(int fd, off_t offset, off_t nbytes, unsigned int flags); /* async_skip=0 */
+
+ssize_t getxattr(const char *path, const char *name, void *value, size_t size, u_int32_t position, int options); /* flags=(options&XATTR_NOFOLLOW?AT_SYMLINK_NOFOLLOW:0) */
+ssize_t fgetxattr(int filedes, const char *name, void *value, size_t size, u_int32_t position, int options);
+int setxattr(const char *path, const char *name, const void *value, size_t size, u_int32_t position, int options); /* flags=0 */
+int fsetxattr(int filedes, const char *name, const void *value, size_t size, u_int32_t position, int options);
+ssize_t listxattr(const char *path, char *list, size_t size, int options); /* flags=0 */
+ssize_t flistxattr(int filedes, char *list, size_t size, int options);
+int removexattr(const char *path, const char *name, int options); /* flags=0 */
+int fremovexattr(int filedes, const char *name, int options);
diff --git a/ports/linux/xattr/pseudo_wrappers.c b/ports/linux/xattr/pseudo_wrappers.c
index 40699d6..e2f4388 100644
--- a/ports/linux/xattr/pseudo_wrappers.c
+++ b/ports/linux/xattr/pseudo_wrappers.c
@@ -62,7 +62,7 @@ static int
posix_permissions(const acl_header *header, int entries, int *extra, int *mode) {
int acl_seen = 0;
if (le32(header->version) != 2) {
- pseudo_diag("Fatal: ACL support no available for header versio %d.\n",
+ pseudo_diag("Fatal: ACL support no available for header version %d.\n",
le32(header->version));
return 1;
}