From 0c7a0cae1d1a763f8c5183f86ee5e53927b07e6d Mon Sep 17 00:00:00 2001 From: Brian Dickens Date: Wed, 18 Oct 2023 04:56:23 -0400 Subject: [PATCH] Fix garbage filetimes reported on Windows by QUERY It turns out the conversion of libuv's time to a windows time is more complex than assumed. Todo: Find a way to test this. --- extensions/filesystem/file-posix.c | 31 ++++++++++++++++++++++++++---- 1 file changed, 27 insertions(+), 4 deletions(-) diff --git a/extensions/filesystem/file-posix.c b/extensions/filesystem/file-posix.c index aa586d2f95..8474850a5c 100644 --- a/extensions/filesystem/file-posix.c +++ b/extensions/filesystem/file-posix.c @@ -523,6 +523,31 @@ REBVAL *Rename_File_Or_Directory(const REBVAL *port, const REBVAL *to) #if TO_WINDOWS + static const int64_t SECS_BETWEEN_1601_AND_1970_EPOCHS = 11644473600LL; + static const int64_t SECS_TO_100NS = 10000000; /* 10^7 */ + + // Convert a time_t value to a win32 FILETIME structure, as described in + // MSDN documentation. time_t is the number of seconds elapsed since + // 00:00 01 January 1970 UTC (Unix epoch), while FILETIME represents a + // 64-bit number of 100-nanosecond intervals that have passed since 00:00 + // 01 January 1601 UTC (win32 epoch). + // + FILETIME LibuvTimeToFileTime( uv_timespec_t uvtime) + { + int64_t result; + FILETIME filetime; + + result = + (cast(int64_t, uvtime.tv_sec) + SECS_BETWEEN_1601_AND_1970_EPOCHS) + * SECS_TO_100NS + + (uvtime.tv_nsec / 100); + + filetime.dwLowDateTime = cast(DWORD, result); + filetime.dwHighDateTime = cast(DWORD, result >> 32); + + return filetime; + } + // // File_Time_To_Rebol: C // @@ -536,10 +561,8 @@ REBVAL *Rename_File_Or_Directory(const REBVAL *port, const REBVAL *to) if (TIME_ZONE_ID_DAYLIGHT == GetTimeZoneInformation(&tzone)) tzone.Bias += tzone.DaylightBias; - FILETIME filetime; - filetime.dwLowDateTime = uvtime.tv_sec; - filetime.dwHighDateTime = uvtime.tv_nsec; - FileTimeToSystemTime(cast(FILETIME *, &uvtime), &stime); + FILETIME filetime = LibuvTimeToFileTime(uvtime); + FileTimeToSystemTime(&filetime, &stime); return rebValue("ensure date! (make-date-ymdsnz", rebI(stime.wYear), // year