1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147
|
/*
* 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
|