diff options
author | Ben Noordhuis <info@bnoordhuis.nl> | 2025-02-21 23:08:15 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2025-02-21 23:08:15 +0100 |
commit | 85b526f56ac0ca5e76de5cbc0e1e9452f73a01d5 (patch) | |
tree | fc5ecdc70e38926c2afcf30b40c84aee47d99420 /src | |
parent | 8a94b7b2ec23abc57c5a0bf36c808bc6dcc0ce4f (diff) | |
download | libuv-85b526f56ac0ca5e76de5cbc0e1e9452f73a01d5.tar.gz libuv-85b526f56ac0ca5e76de5cbc0e1e9452f73a01d5.zip |
unix,win: accept NAN/INFINITY as file timestamps (#4702)
Extend uv_fs_utime, uv_fs_futime and uv_fs_lutime to accept NAN and
INFINITY, with NAN meaning "don't touch the timestamp" and INFINITY
meaning "set to the current timestamp."
Ugly, but it avoids having to add uv_fs_utime2, etc.
UV_FS_UTIME_NOW and UV_FS_UTIME_OMIT constants have been added to make
it more palatable.
Fixes: https://github.com/libuv/libuv/issues/4665
Diffstat (limited to 'src')
-rw-r--r-- | src/unix/fs.c | 99 | ||||
-rw-r--r-- | src/uv-common.h | 19 | ||||
-rw-r--r-- | src/win/fs.c | 25 |
3 files changed, 82 insertions, 61 deletions
diff --git a/src/unix/fs.c b/src/unix/fs.c index 1631d934..717f3fab 100644 --- a/src/unix/fs.c +++ b/src/unix/fs.c @@ -203,8 +203,23 @@ static ssize_t uv__fs_fdatasync(uv_fs_t* req) { } -UV_UNUSED(static struct timespec uv__fs_to_timespec(double time)) { +#if defined(__APPLE__) \ + || defined(_AIX71) \ + || defined(__DragonFly__) \ + || defined(__FreeBSD__) \ + || defined(__HAIKU__) \ + || defined(__NetBSD__) \ + || defined(__OpenBSD__) \ + || defined(__linux__) \ + || defined(__sun) +static struct timespec uv__fs_to_timespec(double time) { struct timespec ts; + + if (uv__isinf(time)) + return (struct timespec){UTIME_NOW, UTIME_NOW}; + if (uv__isnan(time)) + return (struct timespec){UTIME_OMIT, UTIME_OMIT}; + ts.tv_sec = time; ts.tv_nsec = (time - ts.tv_sec) * 1e9; @@ -221,41 +236,23 @@ UV_UNUSED(static struct timespec uv__fs_to_timespec(double time)) { } return ts; } +#endif -UV_UNUSED(static struct timeval uv__fs_to_timeval(double time)) { - struct timeval tv; - tv.tv_sec = time; - tv.tv_usec = (time - tv.tv_sec) * 1e6; - if (tv.tv_usec < 0) { - tv.tv_usec += 1e6; - tv.tv_sec -= 1; - } - return tv; -} static ssize_t uv__fs_futime(uv_fs_t* req) { -#if defined(__linux__) \ +#if defined(__APPLE__) \ || defined(_AIX71) \ - || defined(__HAIKU__) \ - || defined(__GNU__) - struct timespec ts[2]; - ts[0] = uv__fs_to_timespec(req->atime); - ts[1] = uv__fs_to_timespec(req->mtime); - return futimens(req->file, ts); -#elif defined(__APPLE__) \ || defined(__DragonFly__) \ || defined(__FreeBSD__) \ + || defined(__HAIKU__) \ || defined(__NetBSD__) \ || defined(__OpenBSD__) \ + || defined(__linux__) \ || defined(__sun) - struct timeval tv[2]; - tv[0] = uv__fs_to_timeval(req->atime); - tv[1] = uv__fs_to_timeval(req->mtime); -# if defined(__sun) - return futimesat(req->file, NULL, tv); -# else - return futimes(req->file, tv); -# endif + struct timespec ts[2]; + ts[0] = uv__fs_to_timespec(req->atime); + ts[1] = uv__fs_to_timespec(req->mtime); + return futimens(req->file, ts); #elif defined(__MVS__) attrib_t atr; memset(&atr, 0, sizeof(atr)); @@ -1142,25 +1139,20 @@ static ssize_t uv__fs_sendfile(uv_fs_t* req) { static ssize_t uv__fs_utime(uv_fs_t* req) { -#if defined(__linux__) \ - || defined(_AIX71) \ - || defined(__sun) \ - || defined(__HAIKU__) +#if defined(__APPLE__) \ + || defined(_AIX71) \ + || defined(__DragonFly__) \ + || defined(__FreeBSD__) \ + || defined(__HAIKU__) \ + || defined(__NetBSD__) \ + || defined(__OpenBSD__) \ + || defined(__linux__) \ + || defined(__sun) struct timespec ts[2]; ts[0] = uv__fs_to_timespec(req->atime); ts[1] = uv__fs_to_timespec(req->mtime); return utimensat(AT_FDCWD, req->path, ts, 0); -#elif defined(__APPLE__) \ - || defined(__DragonFly__) \ - || defined(__FreeBSD__) \ - || defined(__NetBSD__) \ - || defined(__OpenBSD__) - struct timeval tv[2]; - tv[0] = uv__fs_to_timeval(req->atime); - tv[1] = uv__fs_to_timeval(req->mtime); - return utimes(req->path, tv); -#elif defined(_AIX) \ - && !defined(_AIX71) +#elif defined(_AIX) && !defined(_AIX71) struct utimbuf buf; buf.actime = req->atime; buf.modtime = req->mtime; @@ -1181,24 +1173,19 @@ static ssize_t uv__fs_utime(uv_fs_t* req) { static ssize_t uv__fs_lutime(uv_fs_t* req) { -#if defined(__linux__) || \ - defined(_AIX71) || \ - defined(__sun) || \ - defined(__HAIKU__) || \ - defined(__GNU__) || \ - defined(__OpenBSD__) +#if defined(__APPLE__) \ + || defined(_AIX71) \ + || defined(__DragonFly__) \ + || defined(__FreeBSD__) \ + || defined(__HAIKU__) \ + || defined(__NetBSD__) \ + || defined(__OpenBSD__) \ + || defined(__linux__) \ + || defined(__sun) struct timespec ts[2]; ts[0] = uv__fs_to_timespec(req->atime); ts[1] = uv__fs_to_timespec(req->mtime); return utimensat(AT_FDCWD, req->path, ts, AT_SYMLINK_NOFOLLOW); -#elif defined(__APPLE__) || \ - defined(__DragonFly__) || \ - defined(__FreeBSD__) || \ - defined(__NetBSD__) - struct timeval tv[2]; - tv[0] = uv__fs_to_timeval(req->atime); - tv[1] = uv__fs_to_timeval(req->mtime); - return lutimes(req->path, tv); #else errno = ENOSYS; return -1; diff --git a/src/uv-common.h b/src/uv-common.h index 372f0c4b..8e779ba5 100644 --- a/src/uv-common.h +++ b/src/uv-common.h @@ -31,6 +31,7 @@ #include <stdarg.h> #include <stddef.h> #include <stdint.h> +#include <string.h> #include "uv.h" #include "uv/tree.h" @@ -448,4 +449,22 @@ struct uv__loop_internal_fields_s { # define UV_PTHREAD_MAX_NAMELEN_NP 16 #endif +/* Open-coded so downstream users don't have to link libm. */ +static inline int uv__isinf(double d) { + uint64_t v; + + STATIC_ASSERT(sizeof(v) == sizeof(d)); + memcpy(&v, &d, sizeof(v)); + return (v << 1 >> 53) == 2047 && !(v << 12); +} + +/* Open-coded so downstream users don't have to link libm. */ +static inline int uv__isnan(double d) { + uint64_t v; + + STATIC_ASSERT(sizeof(v) == sizeof(d)); + memcpy(&v, &d, sizeof(v)); + return (v << 1 >> 53) == 2047 && !!(v << 12); +} + #endif /* UV_COMMON_H_ */ diff --git a/src/win/fs.c b/src/win/fs.c index b4ed760e..27248f64 100644 --- a/src/win/fs.c +++ b/src/win/fs.c @@ -2580,14 +2580,29 @@ fchmod_cleanup: INLINE static int fs__utime_handle(HANDLE handle, double atime, double mtime) { - FILETIME filetime_a, filetime_m; + FILETIME filetime_as, *filetime_a = &filetime_as; + FILETIME filetime_ms, *filetime_m = &filetime_ms; + FILETIME now; - TIME_T_TO_FILETIME(atime, &filetime_a); - TIME_T_TO_FILETIME(mtime, &filetime_m); + if (uv__isinf(atime) || uv__isinf(mtime)) + GetSystemTimeAsFileTime(&now); - if (!SetFileTime(handle, NULL, &filetime_a, &filetime_m)) { + if (uv__isinf(atime)) + filetime_a = &now; + else if (uv__isnan(atime)) + filetime_a = NULL; + else + TIME_T_TO_FILETIME(atime, filetime_a); + + if (uv__isinf(mtime)) + filetime_m = &now; + else if (uv__isnan(mtime)) + filetime_m = NULL; + else + TIME_T_TO_FILETIME(mtime, filetime_m); + + if (!SetFileTime(handle, NULL, filetime_a, filetime_m)) return -1; - } return 0; } |