summaryrefslogtreecommitdiff
path: root/src/File.cc
diff options
context:
space:
mode:
authorTatsuhiro Tsujikawa <tatsuhiro.t@gmail.com>2017-11-29 22:20:16 +0900
committerTatsuhiro Tsujikawa <tatsuhiro.t@gmail.com>2017-11-29 22:22:28 +0900
commitcc5469c0478a261f4d39c9fbbd7e70432f4e48d0 (patch)
tree37c70f0cf84aa03466f74b2fa4215dee614f39a9 /src/File.cc
parent795a0474df35c56307151cca5787cb8ae2df06e5 (diff)
mingw: Use SetFileTime to avoid DST adjustment
Diffstat (limited to 'src/File.cc')
-rw-r--r--src/File.cc46
1 files changed, 42 insertions, 4 deletions
diff --git a/src/File.cc b/src/File.cc
index be658cbb..834cab4b 100644
--- a/src/File.cc
+++ b/src/File.cc
@@ -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()