block: Mark bdrv_replace_child_noperm() GRAPH_WRLOCK
[qemu/kevin.git] / hw / 9pfs / 9p-util-darwin.c
blob95146e73546a99431151abf8faec4944f483258c
1 /*
2 * 9p utilities (Darwin Implementation)
4 * This work is licensed under the terms of the GNU GPL, version 2 or later.
5 * See the COPYING file in the top-level directory.
6 */
8 #include "qemu/osdep.h"
9 #include "qemu/xattr.h"
10 #include "qapi/error.h"
11 #include "qemu/error-report.h"
12 #include "9p-util.h"
14 ssize_t fgetxattrat_nofollow(int dirfd, const char *filename, const char *name,
15 void *value, size_t size)
17 int ret;
18 int fd = openat_file(dirfd, filename,
19 O_RDONLY | O_PATH_9P_UTIL | O_NOFOLLOW, 0);
20 if (fd == -1) {
21 return -1;
23 ret = fgetxattr(fd, name, value, size, 0, 0);
24 close_preserve_errno(fd);
25 return ret;
28 ssize_t flistxattrat_nofollow(int dirfd, const char *filename,
29 char *list, size_t size)
31 int ret;
32 int fd = openat_file(dirfd, filename,
33 O_RDONLY | O_PATH_9P_UTIL | O_NOFOLLOW, 0);
34 if (fd == -1) {
35 return -1;
37 ret = flistxattr(fd, list, size, 0);
38 close_preserve_errno(fd);
39 return ret;
42 ssize_t fremovexattrat_nofollow(int dirfd, const char *filename,
43 const char *name)
45 int ret;
46 int fd = openat_file(dirfd, filename, O_PATH_9P_UTIL | O_NOFOLLOW, 0);
47 if (fd == -1) {
48 return -1;
50 ret = fremovexattr(fd, name, 0);
51 close_preserve_errno(fd);
52 return ret;
55 int fsetxattrat_nofollow(int dirfd, const char *filename, const char *name,
56 void *value, size_t size, int flags)
58 int ret;
59 int fd = openat_file(dirfd, filename, O_PATH_9P_UTIL | O_NOFOLLOW, 0);
60 if (fd == -1) {
61 return -1;
63 ret = fsetxattr(fd, name, value, size, 0, flags);
64 close_preserve_errno(fd);
65 return ret;
69 * As long as mknodat is not available on macOS, this workaround
70 * using pthread_fchdir_np is needed.
72 * Radar filed with Apple for implementing mknodat:
73 * rdar://FB9862426 (https://openradar.appspot.com/FB9862426)
75 #if defined CONFIG_PTHREAD_FCHDIR_NP
77 static int create_socket_file_at_cwd(const char *filename, mode_t mode) {
78 int fd, err;
79 struct sockaddr_un addr = {
80 .sun_family = AF_UNIX
83 err = snprintf(addr.sun_path, sizeof(addr.sun_path), "./%s", filename);
84 if (err < 0 || err >= sizeof(addr.sun_path)) {
85 errno = ENAMETOOLONG;
86 return -1;
88 fd = socket(PF_UNIX, SOCK_DGRAM, 0);
89 if (fd == -1) {
90 return fd;
92 err = bind(fd, (struct sockaddr *) &addr, sizeof(addr));
93 if (err == -1) {
94 goto out;
97 * FIXME: Should rather be using descriptor-based fchmod() on the
98 * socket file descriptor above (preferably before bind() call),
99 * instead of path-based fchmodat(), to prevent concurrent transient
100 * state issues between creating the named FIFO file at bind() and
101 * delayed adjustment of permissions at fchmodat(). However currently
102 * macOS (12.x) does not support such operations on socket file
103 * descriptors yet.
105 * Filed report with Apple: FB9997731
107 err = fchmodat(AT_FDCWD, filename, mode, AT_SYMLINK_NOFOLLOW);
108 out:
109 close_preserve_errno(fd);
110 return err;
113 int qemu_mknodat(int dirfd, const char *filename, mode_t mode, dev_t dev)
115 int preserved_errno, err;
117 if (S_ISREG(mode) || !(mode & S_IFMT)) {
118 int fd = openat_file(dirfd, filename, O_CREAT, mode);
119 if (fd == -1) {
120 return fd;
122 close(fd);
123 return 0;
125 if (!pthread_fchdir_np) {
126 error_report_once("pthread_fchdir_np() not available on this version of macOS");
127 errno = ENOTSUP;
128 return -1;
130 if (pthread_fchdir_np(dirfd) < 0) {
131 return -1;
133 if (S_ISSOCK(mode)) {
134 err = create_socket_file_at_cwd(filename, mode);
135 } else {
136 err = mknod(filename, mode, dev);
138 preserved_errno = errno;
139 /* Stop using the thread-local cwd */
140 pthread_fchdir_np(-1);
141 if (err < 0) {
142 errno = preserved_errno;
144 return err;
147 #endif