From 1d41167941932c34eec1c016aeb7ca303813f656 Mon Sep 17 00:00:00 2001 From: Steffen Schuemann Date: Thu, 20 Aug 2020 22:26:56 +0200 Subject: [PATCH] refs #68, experimental support for emscripten --- include/ghc/filesystem.hpp | 25 ++++++++++++++++++++++++- test/CMakeLists.txt | 4 ++++ test/filesystem_test.cpp | 21 ++++++++++++++++++++- 3 files changed, 48 insertions(+), 2 deletions(-) diff --git a/include/ghc/filesystem.hpp b/include/ghc/filesystem.hpp index 477447c..ba9f3c2 100644 --- a/include/ghc/filesystem.hpp +++ b/include/ghc/filesystem.hpp @@ -64,6 +64,9 @@ #define GHC_OS_SYS5R4 #elif defined(BSD) #define GHC_OS_BSD +#elif defined(__EMSCRIPTEN__) +#define GHC_OS_WEB +#include #else #error "Operating system currently not supported!" #endif @@ -590,7 +593,9 @@ enum class copy_options : uint16_t { directories_only = 0x40, create_symlinks = 0x80, +#ifndef GHC_OS_WEB create_hard_links = 0x100 +#endif }; enum class directory_options : uint16_t { @@ -701,10 +706,14 @@ class GHC_FS_API_CLASS directory_entry uintmax_t file_size() const; #endif uintmax_t file_size(std::error_code& ec) const noexcept; + +#ifndef GHC_OS_WEB #ifdef GHC_WITH_EXCEPTIONS uintmax_t hard_link_count() const; #endif uintmax_t hard_link_count(std::error_code& ec) const noexcept; +#endif + #ifdef GHC_WITH_EXCEPTIONS file_time_type last_write_time() const; #endif @@ -934,10 +943,12 @@ GHC_FS_API void create_directory_symlink(const path& to, const path& new_symlink #endif GHC_FS_API void create_directory_symlink(const path& to, const path& new_symlink, std::error_code& ec) noexcept; +#ifndef GHC_OS_WEB #ifdef GHC_WITH_EXCEPTIONS GHC_FS_API void create_hard_link(const path& to, const path& new_hard_link); #endif GHC_FS_API void create_hard_link(const path& to, const path& new_hard_link, std::error_code& ec) noexcept; +#endif #ifdef GHC_WITH_EXCEPTIONS GHC_FS_API void create_symlink(const path& to, const path& new_symlink); @@ -969,10 +980,12 @@ GHC_FS_API uintmax_t file_size(const path& p); #endif GHC_FS_API uintmax_t file_size(const path& p, std::error_code& ec) noexcept; +#ifndef GHC_OS_WEB #ifdef GHC_WITH_EXCEPTIONS GHC_FS_API uintmax_t hard_link_count(const path& p); #endif GHC_FS_API uintmax_t hard_link_count(const path& p, std::error_code& ec) noexcept; +#endif GHC_FS_API bool is_block_file(file_status s) noexcept; #ifdef GHC_WITH_EXCEPTIONS @@ -1815,6 +1828,7 @@ GHC_INLINE void create_symlink(const path& target_name, const path& new_symlink, } } +#ifndef GHC_OS_WEB GHC_INLINE void create_hardlink(const path& target_name, const path& new_hardlink, std::error_code& ec) { if (::link(target_name.c_str(), new_hardlink.c_str()) != 0) { @@ -1822,6 +1836,7 @@ GHC_INLINE void create_hardlink(const path& target_name, const path& new_hardlin } } #endif +#endif template GHC_INLINE file_status file_status_from_st_mode(T mode) @@ -3402,9 +3417,11 @@ GHC_INLINE void copy(const path& from, const path& to, copy_options options, std if ((options & copy_options::create_symlinks) != copy_options::none) { create_symlink(from.is_absolute() ? from : canonical(from, ec), to, ec); } +#ifndef GHC_OS_WEB else if ((options & copy_options::create_hard_links) != copy_options::none) { create_hard_link(from, to, ec); } +#endif else if (is_directory(fs_to)) { copy_file(from, to / from.filename(), options, ec); } @@ -3697,6 +3714,7 @@ GHC_INLINE void create_directory_symlink(const path& to, const path& new_symlink detail::create_symlink(to, new_symlink, true, ec); } +#ifndef GHC_OS_WEB #ifdef GHC_WITH_EXCEPTIONS GHC_INLINE void create_hard_link(const path& to, const path& new_hard_link) { @@ -3712,6 +3730,7 @@ GHC_INLINE void create_hard_link(const path& to, const path& new_hard_link, std: { detail::create_hardlink(to, new_hard_link, ec); } +#endif #ifdef GHC_WITH_EXCEPTIONS GHC_INLINE void create_symlink(const path& to, const path& new_symlink) @@ -3900,6 +3919,7 @@ GHC_INLINE uintmax_t file_size(const path& p, std::error_code& ec) noexcept #endif } +#ifndef GHC_OS_WEB #ifdef GHC_WITH_EXCEPTIONS GHC_INLINE uintmax_t hard_link_count(const path& p) { @@ -3940,6 +3960,7 @@ GHC_INLINE uintmax_t hard_link_count(const path& p, std::error_code& ec) noexcep return ec ? static_cast(-1) : result; #endif } +#endif GHC_INLINE bool is_block_file(file_status s) noexcept { @@ -4176,7 +4197,7 @@ GHC_INLINE void last_write_time(const path& p, file_time_type new_time, std::err times[0].tv_sec = 0; times[0].tv_nsec = UTIME_OMIT; times[1].tv_sec = std::chrono::duration_cast(d).count(); - times[1].tv_nsec = std::chrono::duration_cast(d).count() % 1000000000; + times[1].tv_nsec = 0; //std::chrono::duration_cast(d).count() % 1000000000; if (::utimensat(AT_FDCWD, p.c_str(), times, AT_SYMLINK_NOFOLLOW) != 0) { ec = detail::make_system_error(); } @@ -4945,6 +4966,7 @@ GHC_INLINE uintmax_t directory_entry::file_size(std::error_code& ec) const noexc return filesystem::file_size(path(), ec); } +#ifndef GHC_OS_WEB #ifdef GHC_WITH_EXCEPTIONS GHC_INLINE uintmax_t directory_entry::hard_link_count() const { @@ -4967,6 +4989,7 @@ GHC_INLINE uintmax_t directory_entry::hard_link_count(std::error_code& ec) const #endif return filesystem::hard_link_count(path(), ec); } +#endif #ifdef GHC_WITH_EXCEPTIONS GHC_INLINE file_time_type directory_entry::last_write_time() const diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 9ad6842..72ff653 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -18,12 +18,16 @@ else() add_executable(filesystem_test filesystem_test.cpp catch.hpp) target_link_libraries(filesystem_test ghc_filesystem) target_compile_options(filesystem_test PRIVATE + $<$:-s DISABLE_EXCEPTION_CATCHING=0> $<$:-Wall -Wextra -Wshadow -Wconversion -Wsign-conversion -Wpedantic -Werror> $<$:-Wall -Wextra -Wshadow -Wconversion -Wsign-conversion -Wpedantic -Wno-psabi -Werror> $<$:/WX>) if(CMAKE_CXX_COMPILER_ID MATCHES MSVC) target_compile_definitions(filesystem_test PRIVATE _CRT_SECURE_NO_WARNINGS) endif() + if(EMSCRIPTEN) + set_target_properties(filesystem_test PROPERTIES LINK_FLAGS "-g4 -s DISABLE_EXCEPTION_CATCHING=0 -s ALLOW_MEMORY_GROWTH=1") + endif() ParseAndAddCatchTests(filesystem_test) AddExecutableWithStdFS(std_filesystem_test filesystem_test.cpp catch.hpp) if(WIN32) diff --git a/test/filesystem_test.cpp b/test/filesystem_test.cpp index c449325..55d219e 100644 --- a/test/filesystem_test.cpp +++ b/test/filesystem_test.cpp @@ -1229,9 +1229,11 @@ TEST_CASE("30.10.12 class directory_entry", "[filesystem][directory_entry][fs.di ec.clear(); CHECK(std::abs(std::chrono::duration_cast(de.last_write_time(ec) - now).count()) < 3); CHECK(!ec); +#ifndef GHC_OS_WEB CHECK(de.hard_link_count() == 1); CHECK(de.hard_link_count(ec) == 1); CHECK(!ec); +#endif CHECK_THROWS_AS(de.replace_filename("bar"), fs::filesystem_error); CHECK_NOTHROW(de.replace_filename("foo")); ec.clear(); @@ -1239,9 +1241,11 @@ TEST_CASE("30.10.12 class directory_entry", "[filesystem][directory_entry][fs.di CHECK(ec); auto de2none = fs::directory_entry(); ec.clear(); +#ifndef GHC_OS_WEB CHECK(de2none.hard_link_count(ec) == static_cast(-1)); CHECK_THROWS_AS(de2none.hard_link_count(), fs::filesystem_error); CHECK(ec); +#endif ec.clear(); CHECK_NOTHROW(de2none.last_write_time(ec)); CHECK_THROWS_AS(de2none.last_write_time(), fs::filesystem_error); @@ -1593,6 +1597,7 @@ TEST_CASE("30.10.15.3 copy", "[filesystem][operations][fs.op.copy]") CHECK(fs::is_symlink("dir3/dir2/file3")); #endif } +#ifndef GHC_OS_WEB { TemporaryDirectory t(TempOpt::change_path); std::error_code ec; @@ -1613,6 +1618,7 @@ TEST_CASE("30.10.15.3 copy", "[filesystem][operations][fs.op.copy]") CHECK(fs::exists("dir3/dir2/file3")); CHECK(fs::hard_link_count("dir1/dir2/file3") == f3hl + 1); } +#endif } TEST_CASE("30.10.15.4 copy_file", "[filesystem][operations][fs.op.copy_file]") @@ -1780,6 +1786,7 @@ TEST_CASE("30.10.15.8 create_directory_symlink", "[filesystem][operations][fs.op TEST_CASE("30.10.15.9 create_hard_link", "[filesystem][operations][fs.op.create_hard_link]") { +#ifndef GHC_OS_WEB TemporaryDirectory t(TempOpt::change_path); std::error_code ec; generateFile("foo", 1234); @@ -1793,6 +1800,7 @@ TEST_CASE("30.10.15.9 create_hard_link", "[filesystem][operations][fs.op.create_ CHECK_THROWS_AS(fs::create_hard_link("nofoo", "bar"), fs::filesystem_error); CHECK_NOTHROW(fs::create_hard_link("nofoo", "bar", ec)); CHECK(ec); +#endif } TEST_CASE("30.10.15.10 create_symlink", "[filesystem][operations][fs.op.create_symlink]") @@ -1927,6 +1935,7 @@ TEST_CASE("30.10.15.14 file_size", "[filesystem][operations][fs.op.file_size]") TEST_CASE("30.10.15.15 hard_link_count", "[filesystem][operations][fs.op.hard_link_count]") { +#ifndef GHC_OS_WEB TemporaryDirectory t(TempOpt::change_path); std::error_code ec; #ifdef GHC_OS_WINDOWS @@ -1952,6 +1961,9 @@ TEST_CASE("30.10.15.15 hard_link_count", "[filesystem][operations][fs.op.hard_li CHECK_NOTHROW(fs::hard_link_count(t.path() / "bar", ec)); CHECK(ec); ec.clear(); +#else + WARN("Test for unsupportet features are disabled on JS/Wasm target."); +#endif } class FileTypeMixFixture @@ -1968,7 +1980,7 @@ class FileTypeMixFixture fs::create_symlink("regular", "file_symlink"); fs::create_directory_symlink("directory", "dir_symlink"); } -#ifndef GHC_OS_WINDOWS +#if !defined(GHC_OS_WINDOWS) && !defined(GHC_OS_WEB) REQUIRE(::mkfifo("fifo", 0644) == 0); _hasFifo = true; struct ::sockaddr_un addr; @@ -2271,6 +2283,7 @@ TEST_CASE_METHOD(FileTypeMixFixture, "30.10.15.24 is_symlink", "[filesystem][ope CHECK(!fs::is_symlink(fs::file_status(fs::file_type::unknown))); } +#ifndef GHC_OS_WEB static fs::file_time_type timeFromString(const std::string& str) { struct ::tm tm; @@ -2282,6 +2295,7 @@ static fs::file_time_type timeFromString(const std::string& str) } return from_time_t(std::mktime(&tm)); } +#endif TEST_CASE("30.10.15.25 last_write_time", "[filesystem][operations][fs.op.last_write_time]") { @@ -2304,16 +2318,21 @@ TEST_CASE("30.10.15.25 last_write_time", "[filesystem][operations][fs.op.last_wr // checks that the time of the symlink is fetched CHECK(ft == fs::last_write_time("foo2")); } +#ifndef GHC_OS_WEB auto nt = timeFromString("2015-10-21T04:30:00"); CHECK_NOTHROW(fs::last_write_time(t.path() / "foo", nt)); CHECK(std::abs(std::chrono::duration_cast(fs::last_write_time("foo") - nt).count()) < 1); nt = timeFromString("2015-10-21T04:29:00"); CHECK_NOTHROW(fs::last_write_time("foo", nt, ec)); + std::cout << "about to call last_write_time" << std::endl; CHECK(std::abs(std::chrono::duration_cast(fs::last_write_time("foo") - nt).count()) < 1); CHECK(!ec); + std::cout << "about to call last_write_time" << std::endl; CHECK_THROWS_AS(fs::last_write_time("bar", nt), fs::filesystem_error); + std::cout << "about to call last_write_time" << std::endl; CHECK_NOTHROW(fs::last_write_time("bar", nt, ec)); CHECK(ec); +#endif } TEST_CASE("30.10.15.26 permissions", "[filesystem][operations][fs.op.permissions]")