|  | /* | 
|  | * 9p utilities (Darwin Implementation) | 
|  | * | 
|  | * This work is licensed under the terms of the GNU GPL, version 2 or later. | 
|  | * See the COPYING file in the top-level directory. | 
|  | */ | 
|  |  | 
|  | #include "qemu/osdep.h" | 
|  | #include "qemu/xattr.h" | 
|  | #include "qapi/error.h" | 
|  | #include "qemu/error-report.h" | 
|  | #include "9p-util.h" | 
|  |  | 
|  | ssize_t fgetxattrat_nofollow(int dirfd, const char *filename, const char *name, | 
|  | void *value, size_t size) | 
|  | { | 
|  | int ret; | 
|  | int fd = openat_file(dirfd, filename, | 
|  | O_RDONLY | O_PATH_9P_UTIL | O_NOFOLLOW, 0); | 
|  | if (fd == -1) { | 
|  | return -1; | 
|  | } | 
|  | ret = fgetxattr(fd, name, value, size, 0, 0); | 
|  | close_preserve_errno(fd); | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | ssize_t flistxattrat_nofollow(int dirfd, const char *filename, | 
|  | char *list, size_t size) | 
|  | { | 
|  | int ret; | 
|  | int fd = openat_file(dirfd, filename, | 
|  | O_RDONLY | O_PATH_9P_UTIL | O_NOFOLLOW, 0); | 
|  | if (fd == -1) { | 
|  | return -1; | 
|  | } | 
|  | ret = flistxattr(fd, list, size, 0); | 
|  | close_preserve_errno(fd); | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | ssize_t fremovexattrat_nofollow(int dirfd, const char *filename, | 
|  | const char *name) | 
|  | { | 
|  | int ret; | 
|  | int fd = openat_file(dirfd, filename, O_PATH_9P_UTIL | O_NOFOLLOW, 0); | 
|  | if (fd == -1) { | 
|  | return -1; | 
|  | } | 
|  | ret = fremovexattr(fd, name, 0); | 
|  | close_preserve_errno(fd); | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | int fsetxattrat_nofollow(int dirfd, const char *filename, const char *name, | 
|  | void *value, size_t size, int flags) | 
|  | { | 
|  | int ret; | 
|  | int fd = openat_file(dirfd, filename, O_PATH_9P_UTIL | O_NOFOLLOW, 0); | 
|  | if (fd == -1) { | 
|  | return -1; | 
|  | } | 
|  | ret = fsetxattr(fd, name, value, size, 0, flags); | 
|  | close_preserve_errno(fd); | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | /* | 
|  | * As long as mknodat is not available on macOS, this workaround | 
|  | * using pthread_fchdir_np is needed. | 
|  | * | 
|  | * Radar filed with Apple for implementing mknodat: | 
|  | * rdar://FB9862426 (https://openradar.appspot.com/FB9862426) | 
|  | */ | 
|  | #if defined CONFIG_PTHREAD_FCHDIR_NP | 
|  |  | 
|  | static int create_socket_file_at_cwd(const char *filename, mode_t mode) { | 
|  | int fd, err; | 
|  | struct sockaddr_un addr = { | 
|  | .sun_family = AF_UNIX | 
|  | }; | 
|  |  | 
|  | err = snprintf(addr.sun_path, sizeof(addr.sun_path), "./%s", filename); | 
|  | if (err < 0 || err >= sizeof(addr.sun_path)) { | 
|  | errno = ENAMETOOLONG; | 
|  | return -1; | 
|  | } | 
|  | fd = socket(PF_UNIX, SOCK_DGRAM, 0); | 
|  | if (fd == -1) { | 
|  | return fd; | 
|  | } | 
|  | err = bind(fd, (struct sockaddr *) &addr, sizeof(addr)); | 
|  | if (err == -1) { | 
|  | goto out; | 
|  | } | 
|  | /* | 
|  | * FIXME: Should rather be using descriptor-based fchmod() on the | 
|  | * socket file descriptor above (preferably before bind() call), | 
|  | * instead of path-based fchmodat(), to prevent concurrent transient | 
|  | * state issues between creating the named FIFO file at bind() and | 
|  | * delayed adjustment of permissions at fchmodat(). However currently | 
|  | * macOS (12.x) does not support such operations on socket file | 
|  | * descriptors yet. | 
|  | * | 
|  | * Filed report with Apple: FB9997731 | 
|  | */ | 
|  | err = fchmodat(AT_FDCWD, filename, mode, AT_SYMLINK_NOFOLLOW); | 
|  | out: | 
|  | close_preserve_errno(fd); | 
|  | return err; | 
|  | } | 
|  |  | 
|  | int qemu_mknodat(int dirfd, const char *filename, mode_t mode, dev_t dev) | 
|  | { | 
|  | int preserved_errno, err; | 
|  |  | 
|  | if (S_ISREG(mode) || !(mode & S_IFMT)) { | 
|  | int fd = openat_file(dirfd, filename, O_CREAT, mode); | 
|  | if (fd == -1) { | 
|  | return fd; | 
|  | } | 
|  | close(fd); | 
|  | return 0; | 
|  | } | 
|  | if (!pthread_fchdir_np) { | 
|  | error_report_once("pthread_fchdir_np() not available on this version of macOS"); | 
|  | errno = ENOTSUP; | 
|  | return -1; | 
|  | } | 
|  | if (pthread_fchdir_np(dirfd) < 0) { | 
|  | return -1; | 
|  | } | 
|  | if (S_ISSOCK(mode)) { | 
|  | err = create_socket_file_at_cwd(filename, mode); | 
|  | } else { | 
|  | err = mknod(filename, mode, dev); | 
|  | } | 
|  | preserved_errno = errno; | 
|  | /* Stop using the thread-local cwd */ | 
|  | pthread_fchdir_np(-1); | 
|  | if (err < 0) { | 
|  | errno = preserved_errno; | 
|  | } | 
|  | return err; | 
|  | } | 
|  |  | 
|  | #endif |