fcntl.cpp 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184
  1. /*
  2. * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
  3. * Copyright (c) 2021, sin-ack <sin-ack@protonmail.com>
  4. *
  5. * SPDX-License-Identifier: BSD-2-Clause
  6. */
  7. #include <bits/pthread_cancel.h>
  8. #include <bits/utimens.h>
  9. #include <errno.h>
  10. #include <fcntl.h>
  11. #include <limits.h>
  12. #include <stdarg.h>
  13. #include <string.h>
  14. #include <syscall.h>
  15. #include <time.h>
  16. extern "C" {
  17. int fcntl(int fd, int cmd, ...)
  18. {
  19. __pthread_maybe_cancel();
  20. va_list ap;
  21. va_start(ap, cmd);
  22. uintptr_t extra_arg = va_arg(ap, uintptr_t);
  23. int rc = syscall(SC_fcntl, fd, cmd, extra_arg);
  24. va_end(ap);
  25. __RETURN_WITH_ERRNO(rc, rc, -1);
  26. }
  27. int create_inode_watcher(unsigned flags)
  28. {
  29. int rc = syscall(SC_create_inode_watcher, flags);
  30. __RETURN_WITH_ERRNO(rc, rc, -1);
  31. }
  32. int inode_watcher_add_watch(int fd, char const* path, size_t path_length, unsigned event_mask)
  33. {
  34. Syscall::SC_inode_watcher_add_watch_params params { { path, path_length }, fd, event_mask };
  35. int rc = syscall(SC_inode_watcher_add_watch, &params);
  36. __RETURN_WITH_ERRNO(rc, rc, -1);
  37. }
  38. int inode_watcher_remove_watch(int fd, int wd)
  39. {
  40. int rc = syscall(SC_inode_watcher_remove_watch, fd, wd);
  41. __RETURN_WITH_ERRNO(rc, rc, -1);
  42. }
  43. int creat(char const* path, mode_t mode)
  44. {
  45. __pthread_maybe_cancel();
  46. return open(path, O_CREAT | O_WRONLY | O_TRUNC, mode);
  47. }
  48. int open(char const* path, int options, ...)
  49. {
  50. __pthread_maybe_cancel();
  51. if (!path) {
  52. errno = EFAULT;
  53. return -1;
  54. }
  55. auto path_length = strlen(path);
  56. if (path_length > INT32_MAX) {
  57. errno = EINVAL;
  58. return -1;
  59. }
  60. va_list ap;
  61. va_start(ap, options);
  62. auto mode = (mode_t)va_arg(ap, unsigned);
  63. va_end(ap);
  64. Syscall::SC_open_params params { AT_FDCWD, { path, path_length }, options, mode };
  65. int rc = syscall(SC_open, &params);
  66. __RETURN_WITH_ERRNO(rc, rc, -1);
  67. }
  68. int openat(int dirfd, char const* path, int options, ...)
  69. {
  70. __pthread_maybe_cancel();
  71. if (!path) {
  72. errno = EFAULT;
  73. return -1;
  74. }
  75. auto path_length = strlen(path);
  76. if (path_length > INT32_MAX) {
  77. errno = EINVAL;
  78. return -1;
  79. }
  80. va_list ap;
  81. va_start(ap, options);
  82. auto mode = (mode_t)va_arg(ap, unsigned);
  83. va_end(ap);
  84. Syscall::SC_open_params params { dirfd, { path, path_length }, options, mode };
  85. int rc = syscall(SC_open, &params);
  86. __RETURN_WITH_ERRNO(rc, rc, -1);
  87. }
  88. // https://pubs.opengroup.org/onlinepubs/9699919799/functions/posix_fadvise.html
  89. int posix_fadvise(int fd, off_t offset, off_t len, int advice)
  90. {
  91. // Per POSIX:
  92. // "The posix_fadvise() function shall have no effect on the semantics of other operations on the specified data,
  93. // although it may affect the performance of other operations."
  94. // For now, we simply ignore posix_fadvise() requests. In the future we may use them to optimize performance.
  95. (void)fd;
  96. (void)offset;
  97. (void)len;
  98. (void)advice;
  99. return 0;
  100. }
  101. // https://pubs.opengroup.org/onlinepubs/9699919799/functions/posix_fallocate.html
  102. int posix_fallocate(int fd, off_t offset, off_t len)
  103. {
  104. // posix_fallocate does not set errno.
  105. return -static_cast<int>(syscall(SC_posix_fallocate, fd, &offset, &len));
  106. }
  107. // https://pubs.opengroup.org/onlinepubs/9699919799/functions/utimensat.html
  108. int utimensat(int dirfd, char const* path, struct timespec const times[2], int flag)
  109. {
  110. if (!path) {
  111. errno = EFAULT;
  112. return -1;
  113. }
  114. return __utimens(dirfd, path, times, flag);
  115. }
  116. int __utimens(int fd, char const* path, struct timespec const times[2], int flag)
  117. {
  118. size_t path_length = 0;
  119. if (path) {
  120. path_length = strlen(path);
  121. if (path_length > INT32_MAX) {
  122. errno = EINVAL;
  123. return -1;
  124. }
  125. }
  126. // POSIX allows AT_SYMLINK_NOFOLLOW flag or no flags.
  127. if (flag & ~AT_SYMLINK_NOFOLLOW) {
  128. errno = EINVAL;
  129. return -1;
  130. }
  131. // Return early without error since both changes are to be omitted.
  132. if (times && times[0].tv_nsec == UTIME_OMIT && times[1].tv_nsec == UTIME_OMIT)
  133. return 0;
  134. // According to POSIX, when times is a nullptr, it's equivalent to setting
  135. // both last access time and last modification time to the current time.
  136. // Setting the times argument to nullptr if it matches this case prevents
  137. // the need to copy it in the kernel.
  138. if (times && times[0].tv_nsec == UTIME_NOW && times[1].tv_nsec == UTIME_NOW)
  139. times = nullptr;
  140. if (times) {
  141. for (int i = 0; i < 2; ++i) {
  142. if ((times[i].tv_nsec != UTIME_NOW && times[i].tv_nsec != UTIME_OMIT)
  143. && (times[i].tv_nsec < 0 || times[i].tv_nsec >= 1'000'000'000L)) {
  144. errno = EINVAL;
  145. return -1;
  146. }
  147. }
  148. }
  149. int rc = 0;
  150. if (path) {
  151. // NOTE: fd is treated as dirfd for this syscall.
  152. Syscall::SC_utimensat_params params { fd, { path, path_length }, times, flag };
  153. rc = syscall(SC_utimensat, &params);
  154. } else {
  155. Syscall::SC_futimens_params params { fd, times };
  156. rc = syscall(SC_futimens, &params);
  157. }
  158. __RETURN_WITH_ERRNO(rc, rc, -1);
  159. }
  160. }