diff --git a/CMakeLists.txt b/CMakeLists.txt
index 4ff260b9..7b2d8e01 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -617,6 +617,7 @@ if(WITH_TESTS)
entry_test
error_test
file_access_test
+ filesystem_test
fragment_category_test
incompressible_categorizer_test
integral_value_parser_test
diff --git a/test/filesystem_test.cpp b/test/filesystem_test.cpp
new file mode 100644
index 00000000..7527e591
--- /dev/null
+++ b/test/filesystem_test.cpp
@@ -0,0 +1,180 @@
+/* vim:set ts=2 sw=2 sts=2 et: */
+/**
+ * \author Marcus Holland-Moritz (github@mhxnet.de)
+ * \copyright Copyright (c) Marcus Holland-Moritz
+ *
+ * This file is part of dwarfs.
+ *
+ * dwarfs is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * dwarfs is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with dwarfs. If not, see .
+ */
+
+#include
+
+#include
+#include
+
+#include
+
+#include "dwarfs/filesystem_v2.h"
+#include "dwarfs/mmap.h"
+
+#include "test_logger.h"
+
+using namespace dwarfs;
+
+namespace fs = std::filesystem;
+
+namespace {
+
+auto test_dir = fs::path(TEST_DATA_DIR).make_preferred();
+
+} // namespace
+
+TEST(filesystem, metadata_symlink_win) {
+ test::test_logger lgr;
+
+ auto mm = std::make_shared(test_dir / "winlink.dwarfs");
+ filesystem_v2 fs(lgr, mm);
+
+ auto i1 = fs.find("link.txt");
+ auto i2 = fs.find("dir/link.txt");
+ auto i3 = fs.find("subdir/test.txt");
+
+ ASSERT_TRUE(i1);
+ ASSERT_TRUE(i2);
+ ASSERT_TRUE(i3);
+
+ EXPECT_TRUE(i1->is_symlink());
+ EXPECT_TRUE(i2->is_symlink());
+ EXPECT_TRUE(i3->is_regular_file());
+
+ // readlink_mode::preferred (default)
+ {
+ std::string buf1, buf2;
+ EXPECT_EQ(0, fs.readlink(*i1, &buf1));
+ EXPECT_EQ(0, fs.readlink(*i2, &buf2));
+
+#if defined(_WIN32)
+ EXPECT_EQ("subdir\\test.txt", buf1);
+ EXPECT_EQ("..\\subdir\\test.txt", buf2);
+#else
+ EXPECT_EQ("subdir/test.txt", buf1);
+ EXPECT_EQ("../subdir/test.txt", buf2);
+#endif
+ }
+
+ {
+ std::string buffer;
+ EXPECT_EQ(0, fs.readlink(*i1, &buffer, readlink_mode::raw));
+ EXPECT_EQ("subdir\\test.txt", buffer);
+ EXPECT_EQ(0, fs.readlink(*i2, &buffer, readlink_mode::raw));
+ EXPECT_EQ("..\\subdir\\test.txt", buffer);
+ }
+
+ {
+ std::string buffer;
+ EXPECT_EQ(0, fs.readlink(*i1, &buffer, readlink_mode::unix));
+ EXPECT_EQ("subdir/test.txt", buffer);
+ EXPECT_EQ(0, fs.readlink(*i2, &buffer, readlink_mode::unix));
+ EXPECT_EQ("../subdir/test.txt", buffer);
+ }
+
+ // test error case
+ {
+ std::string buffer;
+ EXPECT_EQ(-EINVAL, fs.readlink(*i3, &buffer));
+ }
+
+ // also test expected interface
+ {
+ auto r = fs.readlink(*i1, readlink_mode::unix);
+ EXPECT_TRUE(r);
+ EXPECT_EQ("subdir/test.txt", *r);
+ }
+
+ {
+ auto r = fs.readlink(*i3);
+ EXPECT_FALSE(r);
+ EXPECT_EQ(-EINVAL, r.error());
+ }
+}
+
+TEST(filesystem, metadata_symlink_unix) {
+ test::test_logger lgr;
+
+ auto mm = std::make_shared(test_dir / "unixlink.dwarfs");
+ filesystem_v2 fs(lgr, mm);
+
+ auto i1 = fs.find("link.txt");
+ auto i2 = fs.find("dir/link.txt");
+ auto i3 = fs.find("subdir/test.txt");
+
+ ASSERT_TRUE(i1);
+ ASSERT_TRUE(i2);
+ ASSERT_TRUE(i3);
+
+ EXPECT_TRUE(i1->is_symlink());
+ EXPECT_TRUE(i2->is_symlink());
+ EXPECT_TRUE(i3->is_regular_file());
+
+ // readlink_mode::preferred (default)
+ {
+ std::string buf1, buf2;
+ EXPECT_EQ(0, fs.readlink(*i1, &buf1));
+ EXPECT_EQ(0, fs.readlink(*i2, &buf2));
+
+#if defined(_WIN32)
+ EXPECT_EQ("subdir\\test.txt", buf1);
+ EXPECT_EQ("..\\subdir\\test.txt", buf2);
+#else
+ EXPECT_EQ("subdir/test.txt", buf1);
+ EXPECT_EQ("../subdir/test.txt", buf2);
+#endif
+ }
+
+ {
+ std::string buffer;
+ EXPECT_EQ(0, fs.readlink(*i1, &buffer, readlink_mode::raw));
+ EXPECT_EQ("subdir/test.txt", buffer);
+ EXPECT_EQ(0, fs.readlink(*i2, &buffer, readlink_mode::raw));
+ EXPECT_EQ("../subdir/test.txt", buffer);
+ }
+
+ {
+ std::string buffer;
+ EXPECT_EQ(0, fs.readlink(*i1, &buffer, readlink_mode::unix));
+ EXPECT_EQ("subdir/test.txt", buffer);
+ EXPECT_EQ(0, fs.readlink(*i2, &buffer, readlink_mode::unix));
+ EXPECT_EQ("../subdir/test.txt", buffer);
+ }
+
+ // test error case
+ {
+ std::string buffer;
+ EXPECT_EQ(-EINVAL, fs.readlink(*i3, &buffer));
+ }
+
+ // also test expected interface
+ {
+ auto r = fs.readlink(*i1, readlink_mode::unix);
+ EXPECT_TRUE(r);
+ EXPECT_EQ("subdir/test.txt", *r);
+ }
+
+ {
+ auto r = fs.readlink(*i3);
+ EXPECT_FALSE(r);
+ EXPECT_EQ(-EINVAL, r.error());
+ }
+}
diff --git a/test/unixlink.dwarfs b/test/unixlink.dwarfs
new file mode 100644
index 00000000..2a208f4e
Binary files /dev/null and b/test/unixlink.dwarfs differ
diff --git a/test/winlink.dwarfs b/test/winlink.dwarfs
new file mode 100644
index 00000000..d753cd4b
Binary files /dev/null and b/test/winlink.dwarfs differ