123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147 |
- /*
- * 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
|