1 /* 2 * 9p utilities (Darwin Implementation) 3 * 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 */ 7 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" 13 14 ssize_t fgetxattrat_nofollow(int dirfd, const char *filename, const char *name, 15 void *value, size_t size) 16 { 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; 22 } 23 ret = fgetxattr(fd, name, value, size, 0, 0); 24 close_preserve_errno(fd); 25 return ret; 26 } 27 28 ssize_t flistxattrat_nofollow(int dirfd, const char *filename, 29 char *list, size_t size) 30 { 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; 36 } 37 ret = flistxattr(fd, list, size, 0); 38 close_preserve_errno(fd); 39 return ret; 40 } 41 42 ssize_t fremovexattrat_nofollow(int dirfd, const char *filename, 43 const char *name) 44 { 45 int ret; 46 int fd = openat_file(dirfd, filename, O_PATH_9P_UTIL | O_NOFOLLOW, 0); 47 if (fd == -1) { 48 return -1; 49 } 50 ret = fremovexattr(fd, name, 0); 51 close_preserve_errno(fd); 52 return ret; 53 } 54 55 int fsetxattrat_nofollow(int dirfd, const char *filename, const char *name, 56 void *value, size_t size, int flags) 57 { 58 int ret; 59 int fd = openat_file(dirfd, filename, O_PATH_9P_UTIL | O_NOFOLLOW, 0); 60 if (fd == -1) { 61 return -1; 62 } 63 ret = fsetxattr(fd, name, value, size, 0, flags); 64 close_preserve_errno(fd); 65 return ret; 66 } 67 68 /* 69 * As long as mknodat is not available on macOS, this workaround 70 * using pthread_fchdir_np is needed. 71 * 72 * Radar filed with Apple for implementing mknodat: 73 * rdar://FB9862426 (https://openradar.appspot.com/FB9862426) 74 */ 75 #if defined CONFIG_PTHREAD_FCHDIR_NP 76 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 81 }; 82 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; 87 } 88 fd = socket(PF_UNIX, SOCK_DGRAM, 0); 89 if (fd == -1) { 90 return fd; 91 } 92 err = bind(fd, (struct sockaddr *) &addr, sizeof(addr)); 93 if (err == -1) { 94 goto out; 95 } 96 /* 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. 104 * 105 * Filed report with Apple: FB9997731 106 */ 107 err = fchmodat(AT_FDCWD, filename, mode, AT_SYMLINK_NOFOLLOW); 108 out: 109 close_preserve_errno(fd); 110 return err; 111 } 112 113 int qemu_mknodat(int dirfd, const char *filename, mode_t mode, dev_t dev) 114 { 115 int preserved_errno, err; 116 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; 121 } 122 close(fd); 123 return 0; 124 } 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; 129 } 130 if (pthread_fchdir_np(dirfd) < 0) { 131 return -1; 132 } 133 if (S_ISSOCK(mode)) { 134 err = create_socket_file_at_cwd(filename, mode); 135 } else { 136 err = mknod(filename, mode, dev); 137 } 138 preserved_errno = errno; 139 /* Stop using the thread-local cwd */ 140 pthread_fchdir_np(-1); 141 if (err < 0) { 142 errno = preserved_errno; 143 } 144 return err; 145 } 146 147 #endif 148