[libcxx-commits] [libcxx] 5c39eeb - [libcxx] [test] Fix filesystem_test_helper.h to compile for windows
Martin Storsjö via libcxx-commits
libcxx-commits at lists.llvm.org
Mon Oct 19 14:07:37 PDT 2020
Author: Martin Storsjö
Date: 2020-10-20T00:07:02+03:00
New Revision: 5c39eebc126dca73c086562bbd9598d4d4c7c197
URL: https://github.com/llvm/llvm-project/commit/5c39eebc126dca73c086562bbd9598d4d4c7c197
DIFF: https://github.com/llvm/llvm-project/commit/5c39eebc126dca73c086562bbd9598d4d4c7c197.diff
LOG: [libcxx] [test] Fix filesystem_test_helper.h to compile for windows
Use .string() instead of .native() in places where we want to combine
paths with std::string.
Convert some methods to take a fs::path as parameter instead of
std::string, for cases where they are called with paths as
parameters (which can't be implicitly converted to std::string if
the path's string_type is wstring).
Differential Revision: https://reviews.llvm.org/D89530
Added:
Modified:
libcxx/test/support/filesystem_test_helper.h
libcxx/utils/libcxx/test/config.py
Removed:
################################################################################
diff --git a/libcxx/test/support/filesystem_test_helper.h b/libcxx/test/support/filesystem_test_helper.h
index 3010b202b2b4..37f0d6bcd367 100644
--- a/libcxx/test/support/filesystem_test_helper.h
+++ b/libcxx/test/support/filesystem_test_helper.h
@@ -4,7 +4,13 @@
#include "filesystem_include.h"
#include <sys/stat.h> // for stat, mkdir, mkfifo
+#ifndef _WIN32
#include <unistd.h> // for ftruncate, link, symlink, getcwd, chdir
+#else
+#include <io.h>
+#include <direct.h>
+#include <windows.h> // for CreateSymbolicLink, CreateHardLink
+#endif
#include <cassert>
#include <cstdio> // for printf
@@ -24,6 +30,28 @@
#endif
namespace utils {
+#ifdef _WIN32
+ inline int mkdir(const char* path, int mode) { (void)mode; return ::_mkdir(path); }
+ inline int ftruncate(int fd, off_t length) { return ::_chsize(fd, length); }
+ inline int symlink(const char* oldname, const char* newname, bool is_dir) {
+ DWORD flags = is_dir ? SYMBOLIC_LINK_FLAG_DIRECTORY : 0;
+ if (CreateSymbolicLinkA(newname, oldname,
+ flags | SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE))
+ return 0;
+ if (GetLastError() != ERROR_INVALID_PARAMETER)
+ return 1;
+ return !CreateSymbolicLinkA(newname, oldname, flags);
+ }
+ inline int link(const char *oldname, const char* newname) {
+ return !CreateHardLinkA(newname, oldname, NULL);
+ }
+#else
+ using ::mkdir;
+ using ::ftruncate;
+ inline int symlink(const char* oldname, const char* newname, bool is_dir) { (void)is_dir; return ::symlink(oldname, newname); }
+ using ::link;
+#endif
+
inline std::string getcwd() {
// Assume that path lengths are not greater than this.
// This should be fine for testing purposes.
@@ -42,7 +70,13 @@ namespace utils {
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 +88,16 @@ struct scoped_test_env
}
~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 +109,12 @@ struct scoped_test_env
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<std::string&>(tmp.native()));
+ return tmp.string();
}
return raw;
}
@@ -85,10 +124,11 @@ struct scoped_test_env
// 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;
+ auto large_file_ftruncate = utils::ftruncate;
using large_file_offset_t = off_t;
#else
auto large_file_fopen = fopen64;
@@ -104,7 +144,12 @@ struct scoped_test_env
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,38 +168,46 @@ struct scoped_test_env
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
+ int ret = utils::mkdir(filename.c_str(), 0777); // rwxrwxrwx mode
assert(ret == 0);
return filename;
}
- std::string create_symlink(std::string source,
- std::string to,
- bool sanitize_source = true) {
+ std::string create_symlink(fs::path source_path,
+ fs::path to_path,
+ bool sanitize_source = true,
+ bool is_dir = false) {
+ std::string source = source_path.string();
+ std::string to = to_path.string();
if (sanitize_source)
source = sanitize_path(std::move(source));
to = sanitize_path(std::move(to));
- int ret = ::symlink(source.c_str(), to.c_str());
+ int ret = utils::symlink(source.c_str(), to.c_str(), is_dir);
assert(ret == 0);
return to;
}
- std::string create_hardlink(std::string source, std::string to) {
+ std::string create_hardlink(fs::path source_path, fs::path to_path) {
+ std::string source = source_path.string();
+ std::string to = to_path.string();
source = sanitize_path(std::move(source));
to = sanitize_path(std::move(to));
- int ret = ::link(source.c_str(), to.c_str());
+ int ret = utils::link(source.c_str(), to.c_str());
assert(ret == 0);
return to;
}
+#ifndef _WIN32
std::string create_fifo(std::string file) {
file = sanitize_path(std::move(file));
int ret = ::mkfifo(file.c_str(), 0666); // rw-rw-rw- mode
assert(ret == 0);
return file;
}
+#endif
// Some platforms doesn't support socket files so we shouldn't even
// allow tests to call this unguarded.
@@ -186,7 +239,7 @@ struct scoped_test_env
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;
@@ -222,7 +275,7 @@ class static_test_env {
env_.create_dir("dir1/dir2/dir3");
env_.create_file("dir1/dir2/dir3/file5");
env_.create_file("dir1/dir2/file4");
- env_.create_symlink("dir3", "dir1/dir2/symlink_to_dir3", false);
+ env_.create_symlink("dir3", "dir1/dir2/symlink_to_dir3", false, true);
env_.create_file("dir1/file1");
env_.create_file("dir1/file2", 42);
env_.create_file("empty_file");
@@ -398,7 +451,7 @@ std::size_t StrLen(CharT const* P) {
// 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<std::string&>(native_ref).reserve(N);
+ const_cast<fs::path::string_type&>(native_ref).reserve(N);
}
template <class Iter1, class Iter2>
@@ -526,8 +579,8 @@ struct ExceptionChecker {
}
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 +590,12 @@ struct ExceptionChecker {
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 "";
diff --git a/libcxx/utils/libcxx/test/config.py b/libcxx/utils/libcxx/test/config.py
index fdc8bbce1cf1..d32b0ee88248 100644
--- a/libcxx/utils/libcxx/test/config.py
+++ b/libcxx/utils/libcxx/test/config.py
@@ -274,6 +274,9 @@ def configure_compile_flags(self):
if self.target_info.is_windows():
# FIXME: Can we remove this?
self.cxx.compile_flags += ['-D_CRT_SECURE_NO_WARNINGS']
+ # Don't warn about using common but nonstandard unprefixed functions
+ # like chdir, fileno.
+ self.cxx.compile_flags += ['-D_CRT_NONSTDC_NO_WARNINGS']
# Required so that tests using min/max don't fail on Windows,
# and so that those tests don't have to be changed to tolerate
# this insanity.
More information about the libcxx-commits
mailing list