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
This commit is contained in:
Родитель
84ad1fd304
Коммит
d25b050379
|
@ -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 \
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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, ×)) {
|
||||
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)) */
|
|
@ -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 */
|
||||
|
|
@ -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 */
|
||||
|
|
|
@ -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, ×)) {
|
||||
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) {
|
||||
|
|
Загрузка…
Ссылка в новой задаче