diff options
author | Jay Satiro <raysatiro@yahoo.com> | 2016-11-11 02:48:52 -0500 |
---|---|---|
committer | Jay Satiro <raysatiro@yahoo.com> | 2016-12-28 21:19:40 -0500 |
commit | ee3c83f39c90126cabb9be896931725c32f22e09 (patch) | |
tree | 6946a6c24c6e25d2612063d0f24b8b6845f5afa6 /src/tool_operate.c | |
parent | 89b789884680134d5090c6de2e6b621e908b1902 (diff) | |
download | curl-ee3c83f39c90126cabb9be896931725c32f22e09.tar.gz |
tool_operate: Fix --remote-time incorrect times on Windows
- Use Windows API SetFileTime to set the file time instead of utime.
Avoid utime on Windows if possible because it may apply a daylight
saving time offset to our UTC file time.
Bug: https://curl.haxx.se/mail/archive-2016-11/0033.html
Reported-by: Tim
Closes https://github.com/curl/curl/pull/1121
Diffstat (limited to 'src/tool_operate.c')
-rw-r--r-- | src/tool_operate.c | 51 |
1 files changed, 48 insertions, 3 deletions
diff --git a/src/tool_operate.c b/src/tool_operate.c index 26662aec5..4fa32bcf3 100644 --- a/src/tool_operate.c +++ b/src/tool_operate.c @@ -1727,20 +1727,65 @@ static CURLcode operate_do(struct GlobalConfig *global, } #endif -#ifdef HAVE_UTIME +#if defined(HAVE_UTIME) || \ + (defined(WIN32) && (CURL_SIZEOF_CURL_OFF_T >= 8)) /* File time can only be set _after_ the file has been closed */ if(!result && config->remote_time && outs.s_isreg && outs.filename) { /* Ask libcurl if we got a remote file time */ long filetime = -1; curl_easy_getinfo(curl, CURLINFO_FILETIME, &filetime); if(filetime >= 0) { +/* Windows utime() may attempt to adjust our unix gmt 'filetime' by a daylight + saving time offset and since it's GMT that is bad behavior. When we have + access to a 64-bit type we can bypass utime and set the times directly. */ +#if defined(WIN32) && (CURL_SIZEOF_CURL_OFF_T >= 8) + /* 910670515199 is the maximum unix filetime that can be used as a + Windows FILETIME without overflow: 30827-12-31T23:59:59. */ + if(filetime <= CURL_OFF_T_C(910670515199)) { + HANDLE hfile = CreateFileA(outs.filename, FILE_WRITE_ATTRIBUTES, + (FILE_SHARE_READ | FILE_SHARE_WRITE | + FILE_SHARE_DELETE), + NULL, OPEN_EXISTING, 0, NULL); + if(hfile != INVALID_HANDLE_VALUE) { + curl_off_t converted = ((curl_off_t)filetime * 10000000) + + CURL_OFF_T_C(116444736000000000); + FILETIME ft; + ft.dwLowDateTime = (DWORD)(converted & 0xFFFFFFFF); + ft.dwHighDateTime = (DWORD)(converted >> 32); + if(!SetFileTime(hfile, NULL, &ft, &ft)) { + fprintf(config->global->errors, + "Failed to set filetime %ld on outfile: " + "SetFileTime failed: GetLastError %u\n", + filetime, GetLastError()); + } + CloseHandle(hfile); + } + else { + fprintf(config->global->errors, + "Failed to set filetime %ld on outfile: " + "CreateFile failed: GetLastError %u\n", + filetime, GetLastError()); + } + } + else { + fprintf(config->global->errors, + "Failed to set filetime %ld on outfile: overflow\n", + filetime); + } +#elif defined(HAVE_UTIME) struct utimbuf times; times.actime = (time_t)filetime; times.modtime = (time_t)filetime; - utime(outs.filename, ×); /* set the time we got */ + if(utime(outs.filename, ×)) { + fprintf(config->global->errors, + "Failed to set filetime %ld on outfile: errno %d\n", + filetime, errno); + } +#endif } } -#endif +#endif /* defined(HAVE_UTIME) || \ + (defined(WIN32) && (CURL_SIZEOF_CURL_OFF_T >= 8)) */ #ifdef USE_METALINK if(!metalink && config->use_metalink && result == CURLE_OK) { |