fcntl.cpp 4.7 KB

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