[libcxx-commits] [libcxx] 6bd3d8a - [libcxx] [test] Fix fs.op.last_write_time for Windows

Martin Storsjö via libcxx-commits libcxx-commits at lists.llvm.org
Wed May 12 12:23:23 PDT 2021


Author: Martin Storsjö
Date: 2021-05-12T22:23:01+03:00
New Revision: 6bd3d8a17cef9108a338ada9b3dbed201bf9c158

URL: https://github.com/llvm/llvm-project/commit/6bd3d8a17cef9108a338ada9b3dbed201bf9c158
DIFF: https://github.com/llvm/llvm-project/commit/6bd3d8a17cef9108a338ada9b3dbed201bf9c158.diff

LOG: [libcxx] [test] Fix fs.op.last_write_time for Windows

Don't use stat and lstat on Windows; lstat is missing, stat only provides
the modification times with second granularity (and does the wrong thing
regarding symlinks). Instead do a minimal reimplementation using the
native windows APIs.

Differential Revision: https://reviews.llvm.org/D101731

Added: 
    

Modified: 
    libcxx/test/std/input.output/filesystems/fs.op.funcs/fs.op.last_write_time/last_write_time.pass.cpp
    libcxx/test/support/filesystem_test_helper.h

Removed: 
    


################################################################################
diff  --git a/libcxx/test/std/input.output/filesystems/fs.op.funcs/fs.op.last_write_time/last_write_time.pass.cpp b/libcxx/test/std/input.output/filesystems/fs.op.funcs/fs.op.last_write_time/last_write_time.pass.cpp
index 54f28aeb01e4d..930dae563b1f5 100644
--- a/libcxx/test/std/input.output/filesystems/fs.op.funcs/fs.op.last_write_time/last_write_time.pass.cpp
+++ b/libcxx/test/std/input.output/filesystems/fs.op.funcs/fs.op.last_write_time/last_write_time.pass.cpp
@@ -8,8 +8,6 @@
 
 // UNSUPPORTED: c++03
 
-// XFAIL: LIBCXX-WINDOWS-FIXME
-
 // The string reported on errors changed, which makes those tests fail when run
 // against already-released libc++'s.
 // XFAIL: use_system_cxx_lib && x86_64-apple-macosx10.15
@@ -34,21 +32,69 @@
 #include "filesystem_test_helper.h"
 
 #include <fcntl.h>
+#ifdef _WIN32
+#include <windows.h>
+#else
 #include <sys/time.h>
 #include <sys/stat.h>
+#endif
 
 using namespace fs;
 
-using TimeSpec = timespec;
-using StatT = struct stat;
-
 using Sec = std::chrono::duration<file_time_type::rep>;
 using Hours = std::chrono::hours;
 using Minutes = std::chrono::minutes;
+using MilliSec = std::chrono::duration<file_time_type::rep, std::milli>;
 using MicroSec = std::chrono::duration<file_time_type::rep, std::micro>;
 using NanoSec = std::chrono::duration<file_time_type::rep, std::nano>;
 using std::chrono::duration_cast;
 
+#ifdef _WIN32
+struct TimeSpec {
+  int64_t tv_sec;
+  int64_t tv_nsec;
+};
+struct StatT {
+  TimeSpec st_atim;
+  TimeSpec st_mtim;
+};
+// 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))
+static 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;
+}
+static int stat_file(const char *path, StatT *buf, int flags) {
+  HANDLE h = CreateFileA(path, FILE_READ_ATTRIBUTES,
+                         FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
+                         nullptr, OPEN_EXISTING,
+                         FILE_FLAG_BACKUP_SEMANTICS | flags, nullptr);
+  if (h == INVALID_HANDLE_VALUE)
+    return -1;
+  int ret = -1;
+  FILE_BASIC_INFO basic;
+  if (GetFileInformationByHandleEx(h, FileBasicInfo, &basic, sizeof(basic))) {
+    buf->st_mtim = filetime_to_timespec(basic.LastWriteTime);
+    buf->st_atim = filetime_to_timespec(basic.LastAccessTime);
+    ret = 0;
+  }
+  CloseHandle(h);
+  return ret;
+}
+static int stat(const char *path, StatT *buf) {
+  return stat_file(path, buf, 0);
+}
+static int lstat(const char *path, StatT *buf) {
+  return stat_file(path, buf, FILE_FLAG_OPEN_REPARSE_POINT);
+}
+#else
+using TimeSpec = timespec;
+using StatT = struct stat;
+#endif
+
 #if defined(__APPLE__)
 TimeSpec extract_mtime(StatT const& st) { return st.st_mtimespec; }
 TimeSpec extract_atime(StatT const& st) { return st.st_atimespec; }
@@ -355,6 +401,11 @@ TEST_CASE(read_last_write_time_static_env_test)
     static_test_env static_env;
     using C = file_time_type::clock;
     file_time_type min = file_time_type::min();
+    // Sleep a little to make sure that static_env.File created above is
+    // strictly older than C::now() even with a coarser clock granularity
+    // in C::now(). (GetSystemTimeAsFileTime on windows has a fairly coarse
+    // granularity.)
+    SleepFor(MilliSec(30));
     {
         file_time_type ret = last_write_time(static_env.File);
         TEST_CHECK(ret != min);

diff  --git a/libcxx/test/support/filesystem_test_helper.h b/libcxx/test/support/filesystem_test_helper.h
index 611daed85affe..7b1fccfd97775 100644
--- a/libcxx/test/support/filesystem_test_helper.h
+++ b/libcxx/test/support/filesystem_test_helper.h
@@ -578,7 +578,7 @@ inline bool ErrorIs(const std::error_code& ec, std::errc First, ErrcT... Rest) {
 
 // Provide our own Sleep routine since std::this_thread::sleep_for is not
 // available in single-threaded mode.
-void SleepFor(std::chrono::seconds dur) {
+template <class Dur> void SleepFor(Dur dur) {
     using namespace std::chrono;
 #if defined(_LIBCPP_HAS_NO_MONOTONIC_CLOCK)
     using Clock = system_clock;


        


More information about the libcxx-commits mailing list