Skip to content

Commit

Permalink
refs #68, experimental support for emscripten
Browse files Browse the repository at this point in the history
  • Loading branch information
gulrak committed Aug 20, 2020
1 parent 2ea0017 commit 1d41167
Show file tree
Hide file tree
Showing 3 changed files with 48 additions and 2 deletions.
25 changes: 24 additions & 1 deletion include/ghc/filesystem.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,9 @@
#define GHC_OS_SYS5R4
#elif defined(BSD)
#define GHC_OS_BSD
#elif defined(__EMSCRIPTEN__)
#define GHC_OS_WEB
#include <wasi/api.h>
#else
#error "Operating system currently not supported!"
#endif
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -1815,13 +1828,15 @@ 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) {
ec = detail::make_system_error();
}
}
#endif
#endif

template <typename T>
GHC_INLINE file_status file_status_from_st_mode(T mode)
Expand Down Expand Up @@ -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);
}
Expand Down Expand Up @@ -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)
{
Expand All @@ -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)
Expand Down Expand Up @@ -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)
{
Expand Down Expand Up @@ -3940,6 +3960,7 @@ GHC_INLINE uintmax_t hard_link_count(const path& p, std::error_code& ec) noexcep
return ec ? static_cast<uintmax_t>(-1) : result;
#endif
}
#endif

GHC_INLINE bool is_block_file(file_status s) noexcept
{
Expand Down Expand Up @@ -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<std::chrono::seconds>(d).count();
times[1].tv_nsec = std::chrono::duration_cast<std::chrono::nanoseconds>(d).count() % 1000000000;
times[1].tv_nsec = 0; //std::chrono::duration_cast<std::chrono::nanoseconds>(d).count() % 1000000000;
if (::utimensat(AT_FDCWD, p.c_str(), times, AT_SYMLINK_NOFOLLOW) != 0) {
ec = detail::make_system_error();
}
Expand Down Expand Up @@ -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
{
Expand All @@ -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
Expand Down
4 changes: 4 additions & 0 deletions test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
$<$<BOOL:${EMSCRIPTEN}>:-s DISABLE_EXCEPTION_CATCHING=0>
$<$<CXX_COMPILER_ID:Clang>:-Wall -Wextra -Wshadow -Wconversion -Wsign-conversion -Wpedantic -Werror>
$<$<CXX_COMPILER_ID:GNU>:-Wall -Wextra -Wshadow -Wconversion -Wsign-conversion -Wpedantic -Wno-psabi -Werror>
$<$<CXX_COMPILER_ID:MSVC>:/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)
Expand Down
21 changes: 20 additions & 1 deletion test/filesystem_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1229,19 +1229,23 @@ TEST_CASE("30.10.12 class directory_entry", "[filesystem][directory_entry][fs.di
ec.clear();
CHECK(std::abs(std::chrono::duration_cast<std::chrono::seconds>(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();
CHECK_NOTHROW(de.replace_filename("bar", ec));
CHECK(ec);
auto de2none = fs::directory_entry();
ec.clear();
#ifndef GHC_OS_WEB
CHECK(de2none.hard_link_count(ec) == static_cast<uintmax_t>(-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);
Expand Down Expand Up @@ -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;
Expand All @@ -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]")
Expand Down Expand Up @@ -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);
Expand All @@ -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]")
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand All @@ -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;
Expand Down Expand Up @@ -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;
Expand All @@ -2282,6 +2295,7 @@ static fs::file_time_type timeFromString(const std::string& str)
}
return from_time_t<fs::file_time_type>(std::mktime(&tm));
}
#endif

TEST_CASE("30.10.15.25 last_write_time", "[filesystem][operations][fs.op.last_write_time]")
{
Expand All @@ -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<std::chrono::seconds>(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<std::chrono::seconds>(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]")
Expand Down

0 comments on commit 1d41167

Please sign in to comment.