diff options
Diffstat (limited to 'src/File.cc')
| -rw-r--r-- | src/File.cc | 46 |
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() |
