From b6b9a6190def53aa53ac816a51034fa1c96ed70b Mon Sep 17 00:00:00 2001 From: Nobuyoshi Nakada Date: Mon, 27 Jun 2022 13:17:36 +0900 Subject: [PATCH] Check availability of `utimensat` on macOS --- file.c | 51 ++++++++++++++++++++++++++++++++++++++++++--------- 1 file 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,11 +2866,17 @@ 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; @@ -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) {