aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorBen Noordhuis <info@bnoordhuis.nl>2025-02-21 23:08:15 +0100
committerGitHub <noreply@github.com>2025-02-21 23:08:15 +0100
commit85b526f56ac0ca5e76de5cbc0e1e9452f73a01d5 (patch)
treefc5ecdc70e38926c2afcf30b40c84aee47d99420 /src
parent8a94b7b2ec23abc57c5a0bf36c808bc6dcc0ce4f (diff)
downloadlibuv-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.c99
-rw-r--r--src/uv-common.h19
-rw-r--r--src/win/fs.c25
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;
}