Check availability of `utimensat` on macOS

This commit is contained in:
Nobuyoshi Nakada 2022-06-27 13:17:36 +09:00
Родитель 6ba52647c3
Коммит b6b9a6190d
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 7CD2805BFA3770C6
1 изменённых файлов: 42 добавлений и 9 удалений

51
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) {