summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Kaufmann <mail@michael-kaufmann.ch>2018-02-05 21:57:39 +0100
committerMichael Kaufmann <mail@michael-kaufmann.ch>2018-02-05 22:02:10 +0100
commitd25b0503795f1fbf557632ce870298f52f2a78c1 (patch)
treef3e73d71451c73ab3d6e39b71a057de92edd91b9
parent84ad1fd3047815f9c6e78728bb351b828eac10b1 (diff)
downloadcurl-d25b0503795f1fbf557632ce870298f52f2a78c1.tar.gz
time-cond: fix reading the file modification time on Windows
On Windows, stat() may adjust the unix file time by a daylight saving time offset. Avoid this by calling GetFileTime() instead. Fixes #2164 Closes #2204
-rw-r--r--src/Makefile.inc2
-rw-r--r--src/tool_cfgable.h2
-rw-r--r--src/tool_filetime.c154
-rw-r--r--src/tool_filetime.h38
-rw-r--r--src/tool_getparam.c17
-rw-r--r--src/tool_operate.c95
6 files changed, 210 insertions, 98 deletions
diff --git a/src/Makefile.inc b/src/Makefile.inc
index d3c7c2bbf..e0506c7f5 100644
--- a/src/Makefile.inc
+++ b/src/Makefile.inc
@@ -37,6 +37,7 @@ CURL_CFILES = \
tool_dirhie.c \
tool_doswin.c \
tool_easysrc.c \
+ tool_filetime.c \
tool_formparse.c \
tool_getparam.c \
tool_getpass.c \
@@ -77,6 +78,7 @@ CURL_HFILES = \
tool_dirhie.h \
tool_doswin.h \
tool_easysrc.h \
+ tool_filetime.h \
tool_formparse.h \
tool_getparam.h \
tool_getpass.h \
diff --git a/src/tool_cfgable.h b/src/tool_cfgable.h
index 713739e7a..0f316775d 100644
--- a/src/tool_cfgable.h
+++ b/src/tool_cfgable.h
@@ -169,7 +169,7 @@ struct OperationConfig {
long proxy_ssl_version;
long ip_version;
curl_TimeCond timecond;
- time_t condtime;
+ curl_off_t condtime;
struct curl_slist *headers;
struct curl_slist *proxyheaders;
curl_mime *mimepost;
diff --git a/src/tool_filetime.c b/src/tool_filetime.c
new file mode 100644
index 000000000..6071e44d2
--- /dev/null
+++ b/src/tool_filetime.c
@@ -0,0 +1,154 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+#include "tool_filetime.h"
+
+#ifdef HAVE_UTIME_H
+# include <utime.h>
+#elif defined(HAVE_SYS_UTIME_H)
+# include <sys/utime.h>
+#endif
+
+curl_off_t getfiletime(const char *filename, FILE *error_stream)
+{
+ curl_off_t result = -1;
+
+/* Windows stat() may attempt to adjust the unix GMT file time 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 stat and get the times directly. */
+#if defined(WIN32) && (SIZEOF_CURL_OFF_T >= 8)
+ HANDLE hfile;
+
+ hfile = CreateFileA(filename, FILE_READ_ATTRIBUTES,
+ (FILE_SHARE_READ | FILE_SHARE_WRITE |
+ FILE_SHARE_DELETE),
+ NULL, OPEN_EXISTING, 0, NULL);
+ if(hfile != INVALID_HANDLE_VALUE) {
+ FILETIME ft;
+ if(GetFileTime(hfile, NULL, NULL, &ft)) {
+ curl_off_t converted = (curl_off_t)ft.dwLowDateTime
+ | ((curl_off_t)ft.dwHighDateTime) << 32;
+
+ if(converted < CURL_OFF_T_C(116444736000000000)) {
+ fprintf(error_stream,
+ "Failed to get filetime: underflow\n");
+ }
+ else {
+ result = (converted - CURL_OFF_T_C(116444736000000000)) / 10000000;
+ }
+ }
+ else {
+ fprintf(error_stream,
+ "Failed to get filetime: "
+ "GetFileTime failed: GetLastError %u\n",
+ (unsigned int)GetLastError());
+ }
+ CloseHandle(hfile);
+ }
+ else if(GetLastError() != ERROR_FILE_NOT_FOUND) {
+ fprintf(error_stream,
+ "Failed to get filetime: "
+ "CreateFile failed: GetLastError %u\n",
+ (unsigned int)GetLastError());
+ }
+#else
+ struct_stat statbuf;
+ if(-1 != stat(filename, &statbuf)) {
+ result = (curl_off_t)statbuf.st_mtime;
+ }
+ else if(errno != ENOENT) {
+ fprintf(error_stream,
+ "Failed to get filetime: %s\n", strerror(errno));
+ }
+#endif
+ return result;
+}
+
+#if defined(HAVE_UTIME) || defined(HAVE_UTIMES) || \
+ (defined(WIN32) && (SIZEOF_CURL_OFF_T >= 8))
+void setfiletime(curl_off_t filetime, const char *filename,
+ FILE *error_stream)
+{
+ if(filetime >= 0) {
+/* Windows utime() may attempt to adjust the unix GMT file time 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) && (SIZEOF_CURL_OFF_T >= 8)
+ HANDLE hfile;
+
+ /* 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)) {
+ fprintf(error_stream,
+ "Failed to set filetime %" CURL_FORMAT_CURL_OFF_T
+ " on outfile: overflow\n", filetime);
+ return;
+ }
+
+ hfile = CreateFileA(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(error_stream,
+ "Failed to set filetime %" CURL_FORMAT_CURL_OFF_T
+ " on outfile: SetFileTime failed: GetLastError %u\n",
+ filetime, (unsigned int)GetLastError());
+ }
+ CloseHandle(hfile);
+ }
+ else {
+ fprintf(error_stream,
+ "Failed to set filetime %" CURL_FORMAT_CURL_OFF_T
+ " on outfile: CreateFile failed: GetLastError %u\n",
+ filetime, (unsigned int)GetLastError());
+ }
+
+#elif defined(HAVE_UTIMES)
+ struct timeval times[2];
+ times[0].tv_sec = times[1].tv_sec = (time_t)filetime;
+ times[0].tv_usec = times[1].tv_usec = 0;
+ if(utimes(filename, times)) {
+ fprintf(error_stream,
+ "Failed to set filetime %" CURL_FORMAT_CURL_OFF_T
+ " on outfile: %s\n", filetime, strerror(errno));
+ }
+
+#elif defined(HAVE_UTIME)
+ struct utimbuf times;
+ times.actime = (time_t)filetime;
+ times.modtime = (time_t)filetime;
+ if(utime(filename, &times)) {
+ fprintf(error_stream,
+ "Failed to set filetime %" CURL_FORMAT_CURL_OFF_T
+ " on outfile: %s\n", filetime, strerror(errno));
+ }
+#endif
+ }
+}
+#endif /* defined(HAVE_UTIME) || defined(HAVE_UTIMES) || \
+ (defined(WIN32) && (SIZEOF_CURL_OFF_T >= 8)) */
diff --git a/src/tool_filetime.h b/src/tool_filetime.h
new file mode 100644
index 000000000..966a70b46
--- /dev/null
+++ b/src/tool_filetime.h
@@ -0,0 +1,38 @@
+#ifndef HEADER_CURL_TOOL_FILETIME_H
+#define HEADER_CURL_TOOL_FILETIME_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+#include "tool_setup.h"
+
+curl_off_t getfiletime(const char *filename, FILE *error_stream);
+
+#if defined(HAVE_UTIME) || defined(HAVE_UTIMES) || \
+ (defined(WIN32) && (SIZEOF_CURL_OFF_T >= 8))
+void setfiletime(curl_off_t filetime, const char *filename,
+ FILE *error_stream);
+#else
+#define setfiletime(a,b,c) Curl_nop_stmt
+#endif /* defined(HAVE_UTIME) || defined(HAVE_UTIMES) || \
+ (defined(WIN32) && (SIZEOF_CURL_OFF_T >= 8)) */
+
+#endif /* HEADER_CURL_TOOL_FILETIME_H */
+
diff --git a/src/tool_getparam.c b/src/tool_getparam.c
index 015d63551..46e7dd3cd 100644
--- a/src/tool_getparam.c
+++ b/src/tool_getparam.c
@@ -31,6 +31,7 @@
#include "tool_cfgable.h"
#include "tool_cb_prg.h"
#include "tool_convert.h"
+#include "tool_filetime.h"
#include "tool_formparse.h"
#include "tool_getparam.h"
#include "tool_helpers.h"
@@ -2087,11 +2088,15 @@ ParameterError getparameter(const char *flag, /* f or -long-flag */
break;
}
now = time(NULL);
- config->condtime = curl_getdate(nextarg, &now);
- if(-1 == (int)config->condtime) {
+ config->condtime = (curl_off_t)curl_getdate(nextarg, &now);
+ if(-1 == config->condtime) {
/* now let's see if it is a file name to get the time from instead! */
- struct_stat statbuf;
- if(-1 == stat(nextarg, &statbuf)) {
+ curl_off_t filetime = getfiletime(nextarg, config->global->errors);
+ if(filetime >= 0) {
+ /* pull the time out from the file */
+ config->condtime = filetime;
+ }
+ else {
/* failed, remove time condition */
config->timecond = CURL_TIMECOND_NONE;
warnf(global,
@@ -2099,10 +2104,6 @@ ParameterError getparameter(const char *flag, /* f or -long-flag */
"a file name). Disabling time condition. "
"See curl_getdate(3) for valid date syntax.\n");
}
- else {
- /* pull the time out from the file */
- config->condtime = statbuf.st_mtime;
- }
}
break;
default: /* unknown flag */
diff --git a/src/tool_operate.c b/src/tool_operate.c
index 5401955af..f326a0d0c 100644
--- a/src/tool_operate.c
+++ b/src/tool_operate.c
@@ -25,12 +25,6 @@
# include <fcntl.h>
#endif
-#ifdef HAVE_UTIME_H
-# include <utime.h>
-#elif defined(HAVE_SYS_UTIME_H)
-# include <sys/utime.h>
-#endif
-
#ifdef HAVE_LOCALE_H
# include <locale.h>
#endif
@@ -56,6 +50,7 @@
#include "tool_dirhie.h"
#include "tool_doswin.h"
#include "tool_easysrc.h"
+#include "tool_filetime.h"
#include "tool_getparam.h"
#include "tool_helpers.h"
#include "tool_homedir.h"
@@ -174,79 +169,6 @@ static curl_off_t VmsSpecialSize(const char *name,
}
#endif /* __VMS */
-#if defined(HAVE_UTIME) || \
- (defined(WIN32) && (SIZEOF_CURL_OFF_T >= 8))
-static void setfiletime(long filetime, const char *filename,
- FILE *error_stream)
-{
- 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) && (SIZEOF_CURL_OFF_T >= 8)
- HANDLE hfile;
-
-#if (SIZEOF_LONG >= 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)) {
- fprintf(error_stream,
- "Failed to set filetime %ld on outfile: overflow\n",
- filetime);
- return;
- }
-#endif /* SIZEOF_LONG >= 8 */
-
- hfile = CreateFileA(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(error_stream,
- "Failed to set filetime %ld on outfile: "
- "SetFileTime failed: GetLastError %u\n",
- filetime, GetLastError());
- }
- CloseHandle(hfile);
- }
- else {
- fprintf(error_stream,
- "Failed to set filetime %ld on outfile: "
- "CreateFile failed: GetLastError %u\n",
- filetime, GetLastError());
- }
-
-#elif defined(HAVE_UTIMES)
- struct timeval times[2];
- times[0].tv_sec = times[1].tv_sec = filetime;
- times[0].tv_usec = times[1].tv_usec = 0;
- if(utimes(filename, times)) {
- fprintf(error_stream,
- "Failed to set filetime %ld on outfile: errno %d\n",
- filetime, errno);
- }
-
-#elif defined(HAVE_UTIME)
- struct utimbuf times;
- times.actime = (time_t)filetime;
- times.modtime = (time_t)filetime;
- if(utime(filename, &times)) {
- fprintf(error_stream,
- "Failed to set filetime %ld on outfile: errno %d\n",
- filetime, errno);
- }
-#endif
- }
-}
-#endif /* defined(HAVE_UTIME) || \
- (defined(WIN32) && (SIZEOF_CURL_OFF_T >= 8)) */
-
#define BUFFER_SIZE (100*1024)
static CURLcode operate_do(struct GlobalConfig *global,
@@ -710,7 +632,7 @@ static CURLcode operate_do(struct GlobalConfig *global,
* to be considered with one appended if implied CC
*/
#ifdef __VMS
- /* Calculate the real upload site for VMS */
+ /* Calculate the real upload size for VMS */
infd = -1;
if(stat(uploadfile, &fileinfo) == 0) {
fileinfo.st_size = VmsSpecialSize(uploadfile, &fileinfo);
@@ -1232,7 +1154,7 @@ static CURLcode operate_do(struct GlobalConfig *global,
#endif
my_setopt_enum(curl, CURLOPT_TIMECONDITION, (long)config->timecond);
- my_setopt(curl, CURLOPT_TIMEVALUE, (long)config->condtime);
+ my_setopt(curl, CURLOPT_TIMEVALUE_LARGE, config->condtime);
my_setopt_str(curl, CURLOPT_CUSTOMREQUEST, config->customrequest);
customrequest_helper(config, config->httpreq, config->customrequest);
my_setopt(curl, CURLOPT_STDERR, global->errors);
@@ -1841,18 +1763,13 @@ static CURLcode operate_do(struct GlobalConfig *global,
}
#endif
-#if defined(HAVE_UTIME) || \
- (defined(WIN32) && (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)
- setfiletime(filetime, outs.filename, config->global->errors);
+ curl_off_t filetime = -1;
+ curl_easy_getinfo(curl, CURLINFO_FILETIME_T, &filetime);
+ setfiletime(filetime, outs.filename, config->global->errors);
}
-#endif /* defined(HAVE_UTIME) || \
- (defined(WIN32) && (SIZEOF_CURL_OFF_T >= 8)) */
#ifdef USE_METALINK
if(!metalink && config->use_metalink && result == CURLE_OK) {