9p-util-darwin.c 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
  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. #include "qemu/osdep.h"
  8. #include "qemu/xattr.h"
  9. #include "qapi/error.h"
  10. #include "qemu/error-report.h"
  11. #include "9p-util.h"
  12. ssize_t fgetxattrat_nofollow(int dirfd, const char *filename, const char *name,
  13. void *value, size_t size)
  14. {
  15. int ret;
  16. int fd = openat_file(dirfd, filename,
  17. O_RDONLY | O_PATH_9P_UTIL | O_NOFOLLOW, 0);
  18. if (fd == -1) {
  19. return -1;
  20. }
  21. ret = fgetxattr(fd, name, value, size, 0, 0);
  22. close_preserve_errno(fd);
  23. return ret;
  24. }
  25. ssize_t flistxattrat_nofollow(int dirfd, const char *filename,
  26. char *list, size_t size)
  27. {
  28. int ret;
  29. int fd = openat_file(dirfd, filename,
  30. O_RDONLY | O_PATH_9P_UTIL | O_NOFOLLOW, 0);
  31. if (fd == -1) {
  32. return -1;
  33. }
  34. ret = flistxattr(fd, list, size, 0);
  35. close_preserve_errno(fd);
  36. return ret;
  37. }
  38. ssize_t fremovexattrat_nofollow(int dirfd, const char *filename,
  39. const char *name)
  40. {
  41. int ret;
  42. int fd = openat_file(dirfd, filename, O_PATH_9P_UTIL | O_NOFOLLOW, 0);
  43. if (fd == -1) {
  44. return -1;
  45. }
  46. ret = fremovexattr(fd, name, 0);
  47. close_preserve_errno(fd);
  48. return ret;
  49. }
  50. int fsetxattrat_nofollow(int dirfd, const char *filename, const char *name,
  51. void *value, size_t size, int flags)
  52. {
  53. int ret;
  54. int fd = openat_file(dirfd, filename, O_PATH_9P_UTIL | O_NOFOLLOW, 0);
  55. if (fd == -1) {
  56. return -1;
  57. }
  58. ret = fsetxattr(fd, name, value, size, 0, flags);
  59. close_preserve_errno(fd);
  60. return ret;
  61. }
  62. /*
  63. * As long as mknodat is not available on macOS, this workaround
  64. * using pthread_fchdir_np is needed.
  65. *
  66. * Radar filed with Apple for implementing mknodat:
  67. * rdar://FB9862426 (https://openradar.appspot.com/FB9862426)
  68. */
  69. #if defined CONFIG_PTHREAD_FCHDIR_NP
  70. static int create_socket_file_at_cwd(const char *filename, mode_t mode) {
  71. int fd, err;
  72. struct sockaddr_un addr = {
  73. .sun_family = AF_UNIX
  74. };
  75. err = snprintf(addr.sun_path, sizeof(addr.sun_path), "./%s", filename);
  76. if (err < 0 || err >= sizeof(addr.sun_path)) {
  77. errno = ENAMETOOLONG;
  78. return -1;
  79. }
  80. fd = socket(PF_UNIX, SOCK_DGRAM, 0);
  81. if (fd == -1) {
  82. return fd;
  83. }
  84. err = bind(fd, (struct sockaddr *) &addr, sizeof(addr));
  85. if (err == -1) {
  86. goto out;
  87. }
  88. /*
  89. * FIXME: Should rather be using descriptor-based fchmod() on the
  90. * socket file descriptor above (preferably before bind() call),
  91. * instead of path-based fchmodat(), to prevent concurrent transient
  92. * state issues between creating the named FIFO file at bind() and
  93. * delayed adjustment of permissions at fchmodat(). However currently
  94. * macOS (12.x) does not support such operations on socket file
  95. * descriptors yet.
  96. *
  97. * Filed report with Apple: FB9997731
  98. */
  99. err = fchmodat(AT_FDCWD, filename, mode, AT_SYMLINK_NOFOLLOW);
  100. out:
  101. close_preserve_errno(fd);
  102. return err;
  103. }
  104. int qemu_mknodat(int dirfd, const char *filename, mode_t mode, dev_t dev)
  105. {
  106. int preserved_errno, err;
  107. if (S_ISREG(mode) || !(mode & S_IFMT)) {
  108. int fd = openat_file(dirfd, filename, O_CREAT, mode);
  109. if (fd == -1) {
  110. return fd;
  111. }
  112. close(fd);
  113. return 0;
  114. }
  115. if (!pthread_fchdir_np) {
  116. error_report_once("pthread_fchdir_np() not available on this version of macOS");
  117. errno = ENOTSUP;
  118. return -1;
  119. }
  120. if (pthread_fchdir_np(dirfd) < 0) {
  121. return -1;
  122. }
  123. if (S_ISSOCK(mode)) {
  124. err = create_socket_file_at_cwd(filename, mode);
  125. } else {
  126. err = mknod(filename, mode, dev);
  127. }
  128. preserved_errno = errno;
  129. /* Stop using the thread-local cwd */
  130. pthread_fchdir_np(-1);
  131. if (err < 0) {
  132. errno = preserved_errno;
  133. }
  134. return err;
  135. }
  136. #endif