157b3910bSKeno Fischer /*
257b3910bSKeno Fischer * 9p utilities (Darwin Implementation)
357b3910bSKeno Fischer *
457b3910bSKeno Fischer * This work is licensed under the terms of the GNU GPL, version 2 or later.
557b3910bSKeno Fischer * See the COPYING file in the top-level directory.
657b3910bSKeno Fischer */
757b3910bSKeno Fischer
857b3910bSKeno Fischer #include "qemu/osdep.h"
957b3910bSKeno Fischer #include "qemu/xattr.h"
10029ed1bdSKeno Fischer #include "qapi/error.h"
11029ed1bdSKeno Fischer #include "qemu/error-report.h"
1257b3910bSKeno Fischer #include "9p-util.h"
1357b3910bSKeno Fischer
fgetxattrat_nofollow(int dirfd,const char * filename,const char * name,void * value,size_t size)1457b3910bSKeno Fischer ssize_t fgetxattrat_nofollow(int dirfd, const char *filename, const char *name,
1557b3910bSKeno Fischer void *value, size_t size)
1657b3910bSKeno Fischer {
1757b3910bSKeno Fischer int ret;
1857b3910bSKeno Fischer int fd = openat_file(dirfd, filename,
1957b3910bSKeno Fischer O_RDONLY | O_PATH_9P_UTIL | O_NOFOLLOW, 0);
2057b3910bSKeno Fischer if (fd == -1) {
2157b3910bSKeno Fischer return -1;
2257b3910bSKeno Fischer }
2357b3910bSKeno Fischer ret = fgetxattr(fd, name, value, size, 0, 0);
2457b3910bSKeno Fischer close_preserve_errno(fd);
2557b3910bSKeno Fischer return ret;
2657b3910bSKeno Fischer }
2757b3910bSKeno Fischer
flistxattrat_nofollow(int dirfd,const char * filename,char * list,size_t size)2857b3910bSKeno Fischer ssize_t flistxattrat_nofollow(int dirfd, const char *filename,
2957b3910bSKeno Fischer char *list, size_t size)
3057b3910bSKeno Fischer {
3157b3910bSKeno Fischer int ret;
3257b3910bSKeno Fischer int fd = openat_file(dirfd, filename,
3357b3910bSKeno Fischer O_RDONLY | O_PATH_9P_UTIL | O_NOFOLLOW, 0);
3457b3910bSKeno Fischer if (fd == -1) {
3557b3910bSKeno Fischer return -1;
3657b3910bSKeno Fischer }
3757b3910bSKeno Fischer ret = flistxattr(fd, list, size, 0);
3857b3910bSKeno Fischer close_preserve_errno(fd);
3957b3910bSKeno Fischer return ret;
4057b3910bSKeno Fischer }
4157b3910bSKeno Fischer
fremovexattrat_nofollow(int dirfd,const char * filename,const char * name)4257b3910bSKeno Fischer ssize_t fremovexattrat_nofollow(int dirfd, const char *filename,
4357b3910bSKeno Fischer const char *name)
4457b3910bSKeno Fischer {
4557b3910bSKeno Fischer int ret;
4657b3910bSKeno Fischer int fd = openat_file(dirfd, filename, O_PATH_9P_UTIL | O_NOFOLLOW, 0);
4757b3910bSKeno Fischer if (fd == -1) {
4857b3910bSKeno Fischer return -1;
4957b3910bSKeno Fischer }
5057b3910bSKeno Fischer ret = fremovexattr(fd, name, 0);
5157b3910bSKeno Fischer close_preserve_errno(fd);
5257b3910bSKeno Fischer return ret;
5357b3910bSKeno Fischer }
5457b3910bSKeno Fischer
fsetxattrat_nofollow(int dirfd,const char * filename,const char * name,void * value,size_t size,int flags)5557b3910bSKeno Fischer int fsetxattrat_nofollow(int dirfd, const char *filename, const char *name,
5657b3910bSKeno Fischer void *value, size_t size, int flags)
5757b3910bSKeno Fischer {
5857b3910bSKeno Fischer int ret;
5957b3910bSKeno Fischer int fd = openat_file(dirfd, filename, O_PATH_9P_UTIL | O_NOFOLLOW, 0);
6057b3910bSKeno Fischer if (fd == -1) {
6157b3910bSKeno Fischer return -1;
6257b3910bSKeno Fischer }
6357b3910bSKeno Fischer ret = fsetxattr(fd, name, value, size, 0, flags);
6457b3910bSKeno Fischer close_preserve_errno(fd);
6557b3910bSKeno Fischer return ret;
6657b3910bSKeno Fischer }
67029ed1bdSKeno Fischer
68029ed1bdSKeno Fischer /*
69029ed1bdSKeno Fischer * As long as mknodat is not available on macOS, this workaround
70029ed1bdSKeno Fischer * using pthread_fchdir_np is needed.
71029ed1bdSKeno Fischer *
72029ed1bdSKeno Fischer * Radar filed with Apple for implementing mknodat:
73029ed1bdSKeno Fischer * rdar://FB9862426 (https://openradar.appspot.com/FB9862426)
74029ed1bdSKeno Fischer */
75029ed1bdSKeno Fischer #if defined CONFIG_PTHREAD_FCHDIR_NP
76029ed1bdSKeno Fischer
create_socket_file_at_cwd(const char * filename,mode_t mode)77055ab893SChristian Schoenebeck static int create_socket_file_at_cwd(const char *filename, mode_t mode) {
78055ab893SChristian Schoenebeck int fd, err;
79055ab893SChristian Schoenebeck struct sockaddr_un addr = {
80055ab893SChristian Schoenebeck .sun_family = AF_UNIX
81055ab893SChristian Schoenebeck };
82055ab893SChristian Schoenebeck
83055ab893SChristian Schoenebeck err = snprintf(addr.sun_path, sizeof(addr.sun_path), "./%s", filename);
84055ab893SChristian Schoenebeck if (err < 0 || err >= sizeof(addr.sun_path)) {
85055ab893SChristian Schoenebeck errno = ENAMETOOLONG;
86055ab893SChristian Schoenebeck return -1;
87055ab893SChristian Schoenebeck }
88055ab893SChristian Schoenebeck fd = socket(PF_UNIX, SOCK_DGRAM, 0);
89055ab893SChristian Schoenebeck if (fd == -1) {
90055ab893SChristian Schoenebeck return fd;
91055ab893SChristian Schoenebeck }
92055ab893SChristian Schoenebeck err = bind(fd, (struct sockaddr *) &addr, sizeof(addr));
93055ab893SChristian Schoenebeck if (err == -1) {
94055ab893SChristian Schoenebeck goto out;
95055ab893SChristian Schoenebeck }
96055ab893SChristian Schoenebeck /*
97055ab893SChristian Schoenebeck * FIXME: Should rather be using descriptor-based fchmod() on the
98055ab893SChristian Schoenebeck * socket file descriptor above (preferably before bind() call),
99055ab893SChristian Schoenebeck * instead of path-based fchmodat(), to prevent concurrent transient
100055ab893SChristian Schoenebeck * state issues between creating the named FIFO file at bind() and
101055ab893SChristian Schoenebeck * delayed adjustment of permissions at fchmodat(). However currently
102055ab893SChristian Schoenebeck * macOS (12.x) does not support such operations on socket file
103055ab893SChristian Schoenebeck * descriptors yet.
104055ab893SChristian Schoenebeck *
105055ab893SChristian Schoenebeck * Filed report with Apple: FB9997731
106055ab893SChristian Schoenebeck */
107055ab893SChristian Schoenebeck err = fchmodat(AT_FDCWD, filename, mode, AT_SYMLINK_NOFOLLOW);
108055ab893SChristian Schoenebeck out:
109055ab893SChristian Schoenebeck close_preserve_errno(fd);
110055ab893SChristian Schoenebeck return err;
111055ab893SChristian Schoenebeck }
112055ab893SChristian Schoenebeck
qemu_mknodat(int dirfd,const char * filename,mode_t mode,dev_t dev)113029ed1bdSKeno Fischer int qemu_mknodat(int dirfd, const char *filename, mode_t mode, dev_t dev)
114029ed1bdSKeno Fischer {
115029ed1bdSKeno Fischer int preserved_errno, err;
116096af171SChristian Schoenebeck
117096af171SChristian Schoenebeck if (S_ISREG(mode) || !(mode & S_IFMT)) {
118096af171SChristian Schoenebeck int fd = openat_file(dirfd, filename, O_CREAT, mode);
119096af171SChristian Schoenebeck if (fd == -1) {
120096af171SChristian Schoenebeck return fd;
121096af171SChristian Schoenebeck }
122096af171SChristian Schoenebeck close(fd);
123096af171SChristian Schoenebeck return 0;
124096af171SChristian Schoenebeck }
125029ed1bdSKeno Fischer if (!pthread_fchdir_np) {
126029ed1bdSKeno Fischer error_report_once("pthread_fchdir_np() not available on this version of macOS");
127*063c75dbSChristian Schoenebeck errno = ENOTSUP;
128*063c75dbSChristian Schoenebeck return -1;
129029ed1bdSKeno Fischer }
130029ed1bdSKeno Fischer if (pthread_fchdir_np(dirfd) < 0) {
131029ed1bdSKeno Fischer return -1;
132029ed1bdSKeno Fischer }
133055ab893SChristian Schoenebeck if (S_ISSOCK(mode)) {
134055ab893SChristian Schoenebeck err = create_socket_file_at_cwd(filename, mode);
135055ab893SChristian Schoenebeck } else {
136029ed1bdSKeno Fischer err = mknod(filename, mode, dev);
137055ab893SChristian Schoenebeck }
138029ed1bdSKeno Fischer preserved_errno = errno;
139029ed1bdSKeno Fischer /* Stop using the thread-local cwd */
140029ed1bdSKeno Fischer pthread_fchdir_np(-1);
141029ed1bdSKeno Fischer if (err < 0) {
142029ed1bdSKeno Fischer errno = preserved_errno;
143029ed1bdSKeno Fischer }
144029ed1bdSKeno Fischer return err;
145029ed1bdSKeno Fischer }
146029ed1bdSKeno Fischer
147029ed1bdSKeno Fischer #endif
148