diff options
-rw-r--r-- | ChangeLog.txt | 5 | ||||
-rw-r--r-- | ports/darwin/guts/fgetxattr.c | 4 | ||||
-rw-r--r-- | ports/darwin/guts/flistxattr.c | 4 | ||||
-rw-r--r-- | ports/darwin/guts/fremovexattr.c | 13 | ||||
-rw-r--r-- | ports/darwin/guts/fsetxattr.c | 4 | ||||
-rw-r--r-- | ports/darwin/guts/getxattr.c | 6 | ||||
-rw-r--r-- | ports/darwin/guts/listxattr.c | 6 | ||||
-rw-r--r-- | ports/darwin/guts/removexattr.c | 13 | ||||
-rw-r--r-- | ports/darwin/guts/setxattr.c | 6 | ||||
-rw-r--r-- | ports/darwin/pseudo_wrappers.c | 321 | ||||
-rw-r--r-- | ports/darwin/wrapfuncs.in | 17 | ||||
-rw-r--r-- | ports/linux/xattr/pseudo_wrappers.c | 2 | ||||
-rw-r--r-- | pseudo.c | 17 | ||||
-rw-r--r-- | pseudo_db.c | 1 |
14 files changed, 371 insertions, 48 deletions
diff --git a/ChangeLog.txt b/ChangeLog.txt index a5c152b..8cba765 100644 --- a/ChangeLog.txt +++ b/ChangeLog.txt @@ -1,6 +1,11 @@ 2014-07-10: * (seebs) Don't pass -L/usr/lib* for sqlite, because that's probably the default. + * (seebs) include sys/xattr.h explicitly for Darwin, also fix things + up so we aren't relying on seeing a declaration for our dummy + wrapper for fgetgrent_r which doesn't exist here. + * (seebs) fix typo in xattr message + * (seebs) make xattr work on Darwin, too. 2014-06-13: * (seebs) don't follow symlinks for lutimes. 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; } @@ -32,6 +32,7 @@ #include <sys/fcntl.h> #include <sys/file.h> #include <sys/wait.h> +#include <sys/xattr.h> #include "pseudo.h" #include "pseudo_ipc.h" @@ -68,17 +69,17 @@ usage(int status) { for (int i = 1; i < PDBG_MAX; i += 2) { unsigned char symbolics[2]; const char *descriptions[2]; - symbolics[1] = pseudo_debug_type_symbolic(i); - symbolics[2] = pseudo_debug_type_symbolic(i + 1); - descriptions[1] = pseudo_debug_type_description(i); - descriptions[2] = pseudo_debug_type_description(i + 1); - if (symbolics[2]) { + symbolics[0] = pseudo_debug_type_symbolic(i); + symbolics[1] = pseudo_debug_type_symbolic(i + 1); + descriptions[0] = pseudo_debug_type_description(i); + descriptions[1] = pseudo_debug_type_description(i + 1); + if (symbolics[1]) { fprintf(f, " %c %-32s %c %-32s\n", - symbolics[1], descriptions[1], - symbolics[2], descriptions[2]); + symbolics[0], descriptions[0], + symbolics[1], descriptions[1]); } else { fprintf(f, " %c %-32s\n", - symbolics[1], descriptions[1]); + symbolics[0], descriptions[0]); } } exit(status); diff --git a/pseudo_db.c b/pseudo_db.c index e361ab2..2638dff 100644 --- a/pseudo_db.c +++ b/pseudo_db.c @@ -21,6 +21,7 @@ #include <stdlib.h> #include <string.h> #include <sys/stat.h> +#include <sys/xattr.h> #include <time.h> #include <unistd.h> |