Merge pull request #1079 from aria2/mingw-fix-remote-time-dst

mingw: Use SetFileTime to avoid DST adjustment
pull/1107/head
Tatsuhiro Tsujikawa 2017-12-02 13:41:01 +09:00 committed by GitHub
commit c882ae3d9c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 42 additions and 4 deletions

View File

@ -122,9 +122,9 @@ bool File::remove()
#ifdef __MINGW32__
namespace {
HANDLE openFile(const std::string& filename)
HANDLE openFile(const std::string& filename, bool readOnly = true)
{
DWORD desiredAccess = GENERIC_READ;
DWORD desiredAccess = GENERIC_READ | (readOnly ? 0 : GENERIC_WRITE);
DWORD sharedMode = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
DWORD creationDisp = OPEN_EXISTING;
return CreateFileW(utf8ToWChar(filename).c_str(), desiredAccess, sharedMode,
@ -317,12 +317,50 @@ bool File::utime(const Time& actime, const Time& modtime) const
struct timeval times[2] = {{actime.getTimeFromEpoch(), 0},
{modtime.getTimeFromEpoch(), 0}};
return utimes(name_.c_str(), times) == 0;
#else // !HAVE_UTIMES
#elif defined(__MINGW32__)
auto hn = openFile(name_, false);
if (hn == INVALID_HANDLE_VALUE) {
auto errNum = GetLastError();
A2_LOG_ERROR(fmt(EX_FILE_OPEN, name_.c_str(),
util::formatLastError(errNum).c_str()));
return false;
}
// Use SetFileTime because Windows _wutime takes DST into
// consideration.
//
// std::chrono::time_point::time_since_epoch returns the amount of
// time between it and epoch Jan 1, 1970. OTOH, FILETIME structure
// expects the epoch as Jan 1, 1601. The resolution is 100
// nanoseconds.
constexpr auto offset = 116444736000000000LL;
uint64_t at = std::chrono::duration_cast<std::chrono::nanoseconds>(
actime.getTime().time_since_epoch())
.count() /
100 +
offset;
uint64_t mt = std::chrono::duration_cast<std::chrono::nanoseconds>(
modtime.getTime().time_since_epoch())
.count() /
100 +
offset;
FILETIME att{static_cast<DWORD>(at & 0xffffffff),
static_cast<DWORD>(at >> 32)};
FILETIME mtt{static_cast<DWORD>(mt & 0xffffffff),
static_cast<DWORD>(mt >> 32)};
auto rv = SetFileTime(hn, nullptr, &att, &mtt);
if (!rv) {
auto errNum = GetLastError();
A2_LOG_ERROR(fmt("SetFileTime failed, cause: %s",
util::formatLastError(errNum).c_str()));
}
CloseHandle(hn);
return rv;
#else // !defined(HAVE_UTIMES) && !defined(__MINGW32__)
a2utimbuf ub;
ub.actime = actime.getTimeFromEpoch();
ub.modtime = modtime.getTimeFromEpoch();
return a2utime(utf8ToWChar(name_).c_str(), &ub) == 0;
#endif // !HAVE_UTIMES
#endif // !defined(HAVE_UTIMES) && !defined(__MINGW32__)
}
Time File::getModifiedTime()