Index: libcxx/test/support/filesystem_test_helper.h =================================================================== --- libcxx/test/support/filesystem_test_helper.h +++ libcxx/test/support/filesystem_test_helper.h @@ -4,7 +4,12 @@ #include "filesystem_include.h" #include // for stat, mkdir, mkfifo +#ifndef _WIN32 #include // for ftruncate, link, symlink, getcwd, chdir +#else +#include +#include +#endif #include #include // for printf @@ -18,11 +23,21 @@ #include "format_string.h" // For creating socket files -#if !defined(__FreeBSD__) && !defined(__APPLE__) +#if !defined(__FreeBSD__) && !defined(__APPLE__) && !defined(_WIN32) # include # include #endif +#ifdef _WIN32 +// MSVC headers warn if using the versions without a leading underscore. +// mkdir takes one parameter less, and instead of ftruncate there's _chsize. +#define mkdir(a, b) _mkdir(a) +#define fileno _fileno +#define getcwd _getcwd +#define chdir _chdir +#define ftruncate _chsize +#endif + namespace utils { inline std::string getcwd() { // Assume that path lengths are not greater than this. @@ -42,7 +57,13 @@ struct scoped_test_env { scoped_test_env() : test_root(available_cwd_path()) { - std::string cmd = "mkdir -p " + test_root.native(); +#ifdef _WIN32 + // Windows mkdir can create multiple recursive directories + // if needed. + std::string cmd = "mkdir " + test_root.string(); +#else + std::string cmd = "mkdir -p " + test_root.string(); +#endif int ret = std::system(cmd.c_str()); assert(ret == 0); @@ -54,11 +75,16 @@ } ~scoped_test_env() { - std::string cmd = "chmod -R 777 " + test_root.native(); +#ifdef _WIN32 + std::string cmd = "rmdir /s /q " + test_root.string(); + int ret; +#else + std::string cmd = "chmod -R 777 " + test_root.string(); int ret = std::system(cmd.c_str()); assert(ret == 0); - cmd = "rm -r " + test_root.native(); + cmd = "rm -r " + test_root.string(); +#endif ret = std::system(cmd.c_str()); assert(ret == 0); } @@ -70,12 +96,12 @@ std::string sanitize_path(std::string raw) { assert(raw.find("..") == std::string::npos); - std::string const& root = test_root.native(); + std::string root = test_root.string(); if (root.compare(0, root.size(), raw, 0, root.size()) != 0) { assert(raw.front() != '\\'); fs::path tmp(test_root); tmp /= raw; - return std::move(const_cast(tmp.native())); + return tmp.string(); } return raw; } @@ -85,8 +111,9 @@ // but the caller is not (std::filesystem also uses uintmax_t rather than // off_t). On a 32-bit system this allows us to create a file larger than // 2GB. - std::string create_file(std::string filename, uintmax_t size = 0) { -#if defined(__LP64__) + std::string create_file(fs::path filename_path, uintmax_t size = 0) { + std::string filename = filename_path.string(); +#if defined(__LP64__) || defined(_WIN32) auto large_file_fopen = fopen; auto large_file_ftruncate = ftruncate; using large_file_offset_t = off_t; @@ -104,7 +131,12 @@ abort(); } - FILE* file = large_file_fopen(filename.c_str(), "we"); +#ifndef _WIN32 +#define FOPEN_CLOEXEC_FLAG "e" +#else +#define FOPEN_CLOEXEC_FLAG "" +#endif + FILE* file = large_file_fopen(filename.c_str(), "w" FOPEN_CLOEXEC_FLAG); if (file == nullptr) { fprintf(stderr, "fopen %s failed: %s\n", filename.c_str(), strerror(errno)); @@ -123,13 +155,15 @@ return filename; } - std::string create_dir(std::string filename) { + std::string create_dir(fs::path filename_path) { + std::string filename = filename_path.string(); filename = sanitize_path(std::move(filename)); int ret = ::mkdir(filename.c_str(), 0777); // rwxrwxrwx mode assert(ret == 0); return filename; } +#ifndef _WIN32 std::string create_symlink(std::string source, std::string to, bool sanitize_source = true) { @@ -155,10 +189,11 @@ assert(ret == 0); return file; } +#endif // OS X and FreeBSD doesn't support socket files so we shouldn't even // allow tests to call this unguarded. -#if !defined(__FreeBSD__) && !defined(__APPLE__) +#if !defined(__FreeBSD__) && !defined(__APPLE__) && !defined(_WIN32) std::string create_socket(std::string file) { file = sanitize_path(std::move(file)); @@ -186,7 +221,7 @@ fs::path const base = tmp / cwd.filename(); int i = 0; fs::path p = base / ("static_env." + std::to_string(i)); - while (utils::exists(p)) { + while (utils::exists(p.string())) { p = fs::path(base) / ("static_env." + std::to_string(++i)); } return p; @@ -215,20 +250,26 @@ scoped_test_env env_; public: static_test_env() { +#ifndef _WIN32 env_.create_symlink("dne", "bad_symlink", false); +#endif env_.create_dir("dir1"); env_.create_dir("dir1/dir2"); env_.create_file("dir1/dir2/afile3"); env_.create_dir("dir1/dir2/dir3"); env_.create_file("dir1/dir2/dir3/file5"); env_.create_file("dir1/dir2/file4"); +#ifndef _WIN32 env_.create_symlink("dir3", "dir1/dir2/symlink_to_dir3", false); +#endif env_.create_file("dir1/file1"); env_.create_file("dir1/file2", 42); env_.create_file("empty_file"); env_.create_file("non_empty_file", 42); +#ifndef _WIN32 env_.create_symlink("dir1", "symlink_to_dir", false); env_.create_symlink("empty_file", "symlink_to_empty_file", false); +#endif } const fs::path Root = env_.test_root; @@ -273,7 +314,9 @@ const std::vector DirIterationListDepth1 = { makePath("dir1/dir2/afile3"), makePath("dir1/dir2/dir3"), +#ifndef _WIN32 makePath("dir1/dir2/symlink_to_dir3"), +#endif makePath("dir1/dir2/file4"), }; @@ -283,7 +326,9 @@ makePath("dir1/file2"), makePath("dir1/dir2/afile3"), makePath("dir1/dir2/dir3"), +#ifndef _WIN32 makePath("dir1/dir2/symlink_to_dir3"), +#endif makePath("dir1/dir2/file4"), makePath("dir1/dir2/dir3/file5") }; @@ -296,8 +341,10 @@ makePath("dir1/dir2/dir3"), makePath("dir1/dir2/file4"), makePath("dir1/dir2/dir3/file5"), +#ifndef _WIN32 makePath("dir1/dir2/symlink_to_dir3"), makePath("dir1/dir2/symlink_to_dir3/file5"), +#endif }; }; @@ -398,7 +445,7 @@ // This hack forces path to allocate enough memory. inline void PathReserve(fs::path& p, std::size_t N) { auto const& native_ref = p.native(); - const_cast(native_ref).reserve(N); + const_cast(native_ref).reserve(N); } template @@ -526,8 +573,8 @@ } auto transform_path = [](const fs::path& p) { if (p.native().empty()) - return "\"\""; - return p.c_str(); + return std::string("\"\""); + return p.string(); }; std::string format = [&]() -> std::string { switch (num_paths) { @@ -537,12 +584,12 @@ case 1: return format_string("filesystem error: in %s: %s%s [%s]", func_name, additional_msg, message, - transform_path(expected_path1)); + transform_path(expected_path1).c_str()); case 2: return format_string("filesystem error: in %s: %s%s [%s] [%s]", func_name, additional_msg, message, - transform_path(expected_path1), - transform_path(expected_path2)); + transform_path(expected_path1).c_str(), + transform_path(expected_path2).c_str()); default: TEST_CHECK(false && "unexpected case"); return "";