summaryrefslogtreecommitdiff
path: root/file.c
diff options
context:
space:
mode:
authorNobuyoshi Nakada <nobu@ruby-lang.org>2022-06-27 13:17:36 +0900
committerNobuyoshi Nakada <nobu@ruby-lang.org>2022-06-27 17:52:13 +0900
commitb6b9a6190def53aa53ac816a51034fa1c96ed70b (patch)
tree42512ff6c911c0f54a89200662c75d76010764e3 /file.c
parent6ba52647c3d2b3a0060e0b0edc95f46c77a11944 (diff)
Check availability of `utimensat` on macOS
Diffstat (limited to 'file.c')
-rw-r--r--file.c51
1 files changed, 42 insertions, 9 deletions
diff --git a/file.c b/file.c
index e92ceeabe1..8ed0789d43 100644
--- a/file.c
+++ b/file.c
@@ -2833,6 +2833,31 @@ utime_failed(struct apply_arg *aa)
#if defined(HAVE_UTIMES)
+# if defined(__APPLE__) && \
+ (!defined(MAC_OS_X_VERSION_13_0) || (MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_13_0))
+
+# if defined(__has_attribute) && __has_attribute(availability)
+typedef int utimensat_func(int, const char *, const struct timespec [2], int);
+
+RBIMPL_WARNING_PUSH();
+RBIMPL_WARNING_IGNORED(-Wunguarded-availability-new);
+static inline utimensat_func *
+rb_utimensat(void)
+{
+ return &utimensat;
+}
+RBIMPL_WARNING_POP();
+
+# define utimensat rb_utimensat()
+# else /* __API_AVAILABLE macro does nothing on gcc */
+__attribute__((weak)) int utimensat(int, const char *, const struct timespec [2], int);
+# endif
+
+# define utimensat_available_p() (utimensat != NULL)
+# else
+# define utimensat_available_p() 1
+# endif
+
static int
utime_internal(const char *path, void *arg)
{
@@ -2841,12 +2866,18 @@ utime_internal(const char *path, void *arg)
struct timeval tvbuf[2], *tvp = NULL;
#if defined(HAVE_UTIMENSAT)
+# if defined(__APPLE__)
+ const int try_utimensat = utimensat != NULL;
+ const int try_utimensat_follow = utimensat != NULL;
+# else
+# define TRY_UTIMENSAT 1
static int try_utimensat = 1;
# ifdef AT_SYMLINK_NOFOLLOW
static int try_utimensat_follow = 1;
# else
const int try_utimensat_follow = 0;
# endif
+# endif
int flags = 0;
if (v->follow ? try_utimensat_follow : try_utimensat) {
@@ -2856,20 +2887,22 @@ utime_internal(const char *path, void *arg)
}
# endif
- if (utimensat(AT_FDCWD, path, tsp, flags) < 0) {
- if (errno == ENOSYS) {
+ int result = utimensat(AT_FDCWD, path, tsp, flags);
+# ifdef TRY_UTIMENSAT
+ if (result < 0 && errno == ENOSYS) {
# ifdef AT_SYMLINK_NOFOLLOW
- try_utimensat_follow = 0;
+ try_utimensat_follow = 0;
# endif
- if (!v->follow)
- try_utimensat = 0;
- goto no_utimensat;
- }
- return -1; /* calls utime_failed */
+ if (!v->follow)
+ try_utimensat = 0;
}
- return 0;
+ else
+# endif
+ return result;
}
+# ifdef TRY_UTIMENSAT
no_utimensat:
+# endif
#endif
if (tsp) {