diff --git a/libcxx/src/filesystem/file_descriptor.h b/libcxx/src/filesystem/file_descriptor.h --- a/libcxx/src/filesystem/file_descriptor.h +++ b/libcxx/src/filesystem/file_descriptor.h @@ -18,6 +18,7 @@ #include "error.h" #include "posix_compat.h" +#include "time_utils.h" #if defined(_LIBCPP_WIN32API) # define WIN32_LEAN_AND_MEAN diff --git a/libcxx/src/filesystem/filesystem_clock.cpp b/libcxx/src/filesystem/filesystem_clock.cpp --- a/libcxx/src/filesystem/filesystem_clock.cpp +++ b/libcxx/src/filesystem/filesystem_clock.cpp @@ -11,7 +11,7 @@ #include #include -#include "posix_compat.h" // TimeSpec +#include "time_utils.h" #if defined(_LIBCPP_WIN32API) # define WIN32_LEAN_AND_MEAN diff --git a/libcxx/src/filesystem/posix_compat.h b/libcxx/src/filesystem/posix_compat.h --- a/libcxx/src/filesystem/posix_compat.h +++ b/libcxx/src/filesystem/posix_compat.h @@ -28,6 +28,7 @@ #include #include "error.h" +#include "time_utils.h" #if defined(_LIBCPP_WIN32API) # define WIN32_LEAN_AND_MEAN @@ -79,41 +80,6 @@ namespace detail { -#if defined(_LIBCPP_WIN32API) -// Various C runtime versions (UCRT, or the legacy msvcrt.dll used by -// some mingw toolchains) provide different stat function implementations, -// with a number of limitations with respect to what we want from the -// stat function. Instead provide our own which does exactly what we want, -// along with our own stat structure and flag macros. - -struct TimeSpec { - int64_t tv_sec; - int64_t tv_nsec; -}; -struct StatT { - unsigned st_mode; - TimeSpec st_atim; - TimeSpec st_mtim; - uint64_t st_dev; // FILE_ID_INFO::VolumeSerialNumber - struct FileIdStruct { - unsigned char id[16]; // FILE_ID_INFO::FileId - bool operator==(const FileIdStruct &other) const { - for (int i = 0; i < 16; i++) - if (id[i] != other.id[i]) - return false; - return true; - } - } st_ino; - uint32_t st_nlink; - uintmax_t st_size; -}; - -#else -using TimeSpec = struct timespec; -using TimeVal = struct timeval; -using StatT = struct stat; -#endif - #if defined(_LIBCPP_WIN32API) // Various C runtime header sets provide more or less of these. As we @@ -156,35 +122,6 @@ #define O_NONBLOCK 0 - -// There were 369 years and 89 leap days from the Windows epoch -// (1601) to the Unix epoch (1970). -#define FILE_TIME_OFFSET_SECS (uint64_t(369 * 365 + 89) * (24 * 60 * 60)) - -inline TimeSpec filetime_to_timespec(LARGE_INTEGER li) { - TimeSpec ret; - ret.tv_sec = li.QuadPart / 10000000 - FILE_TIME_OFFSET_SECS; - ret.tv_nsec = (li.QuadPart % 10000000) * 100; - return ret; -} - -inline TimeSpec filetime_to_timespec(FILETIME ft) { - LARGE_INTEGER li; - li.LowPart = ft.dwLowDateTime; - li.HighPart = ft.dwHighDateTime; - return filetime_to_timespec(li); -} - -inline FILETIME timespec_to_filetime(TimeSpec ts) { - LARGE_INTEGER li; - li.QuadPart = - ts.tv_nsec / 100 + (ts.tv_sec + FILE_TIME_OFFSET_SECS) * 10000000; - FILETIME ft; - ft.dwLowDateTime = li.LowPart; - ft.dwHighDateTime = li.HighPart; - return ft; -} - inline int set_errno(int e = GetLastError()) { errno = static_cast(__win_err_to_errc(e)); return -1; diff --git a/libcxx/src/filesystem/time_utils.h b/libcxx/src/filesystem/time_utils.h --- a/libcxx/src/filesystem/time_utils.h +++ b/libcxx/src/filesystem/time_utils.h @@ -21,13 +21,14 @@ #include "error.h" #include "format_string.h" -#include "posix_compat.h" #if defined(_LIBCPP_WIN32API) # define WIN32_LEAN_AND_MEAN # define NOMINMAX # include #else +# include +# include # include // for ::utimes as used in __last_write_time #endif @@ -40,6 +41,82 @@ namespace detail { +#if defined(_LIBCPP_WIN32API) +// Various C runtime versions (UCRT, or the legacy msvcrt.dll used by +// some mingw toolchains) provide different stat function implementations, +// with a number of limitations with respect to what we want from the +// stat function. Instead provide our own which does exactly what we want, +// along with our own stat structure and flag macros. + +struct TimeSpec { + int64_t tv_sec; + int64_t tv_nsec; +}; +struct StatT { + unsigned st_mode; + TimeSpec st_atim; + TimeSpec st_mtim; + uint64_t st_dev; // FILE_ID_INFO::VolumeSerialNumber + struct FileIdStruct { + unsigned char id[16]; // FILE_ID_INFO::FileId + bool operator==(const FileIdStruct &other) const { + for (int i = 0; i < 16; i++) + if (id[i] != other.id[i]) + return false; + return true; + } + } st_ino; + uint32_t st_nlink; + uintmax_t st_size; +}; + +// There were 369 years and 89 leap days from the Windows epoch +// (1601) to the Unix epoch (1970). +#define FILE_TIME_OFFSET_SECS (uint64_t(369 * 365 + 89) * (24 * 60 * 60)) + +inline TimeSpec filetime_to_timespec(LARGE_INTEGER li) { + TimeSpec ret; + ret.tv_sec = li.QuadPart / 10000000 - FILE_TIME_OFFSET_SECS; + ret.tv_nsec = (li.QuadPart % 10000000) * 100; + return ret; +} + +inline TimeSpec filetime_to_timespec(FILETIME ft) { + LARGE_INTEGER li; + li.LowPart = ft.dwLowDateTime; + li.HighPart = ft.dwHighDateTime; + return filetime_to_timespec(li); +} + +inline FILETIME timespec_to_filetime(TimeSpec ts) { + LARGE_INTEGER li; + li.QuadPart = + ts.tv_nsec / 100 + (ts.tv_sec + FILE_TIME_OFFSET_SECS) * 10000000; + FILETIME ft; + ft.dwLowDateTime = li.LowPart; + ft.dwHighDateTime = li.HighPart; + return ft; +} + +#else +using TimeSpec = struct timespec; +using TimeVal = struct timeval; +using StatT = struct stat; + +inline TimeVal make_timeval(TimeSpec const& ts) { + using namespace chrono; + auto Convert = [](long nsec) { + using int_type = decltype(std::declval().tv_usec); + auto dur = duration_cast(nanoseconds(nsec)).count(); + return static_cast(dur); + }; + TimeVal TV = {}; + TV.tv_sec = ts.tv_sec; + TV.tv_usec = Convert(ts.tv_nsec); + return TV; +} +#endif + using chrono::duration; using chrono::duration_cast; @@ -252,20 +329,9 @@ inline TimeSpec extract_atime(StatT const& st) { return st.st_atim; } #endif -#if !defined(_LIBCPP_WIN32API) -inline TimeVal make_timeval(TimeSpec const& ts) { - using namespace chrono; - auto Convert = [](long nsec) { - using int_type = decltype(std::declval().tv_usec); - auto dur = duration_cast(nanoseconds(nsec)).count(); - return static_cast(dur); - }; - TimeVal TV = {}; - TV.tv_sec = ts.tv_sec; - TV.tv_usec = Convert(ts.tv_nsec); - return TV; -} +#ifndef _LIBCPP_HAS_NO_FILESYSTEM +#if !defined(_LIBCPP_WIN32API) inline bool posix_utimes(const path& p, std::array const& TS, error_code& ec) { TimeVal ConvertedTS[2] = {make_timeval(TS[0]), make_timeval(TS[1])}; @@ -310,6 +376,8 @@ return fs_time::convert_from_timespec(ts); } +#endif // !_LIBCPP_HAS_NO_FILESYSTEM + } // end namespace detail _LIBCPP_END_NAMESPACE_FILESYSTEM