From 24e658aa884cb91bb9918487ba0e9bb51d7bf70f Mon Sep 17 00:00:00 2001 From: Arvid Norberg Date: Mon, 21 Oct 2024 11:44:55 +0200 Subject: [PATCH] fix tests to work on linux ZFS --- test/test_copy_file.cpp | 59 ++----------------------- test/test_storage.cpp | 22 ++++++++-- test/test_utils.cpp | 95 +++++++++++++++++++++++++++++++++++++++++ test/test_utils.hpp | 3 ++ 4 files changed, 120 insertions(+), 59 deletions(-) diff --git a/test/test_copy_file.cpp b/test/test_copy_file.cpp index 9a1dfbb2be0..cf305e7400e 100644 --- a/test/test_copy_file.cpp +++ b/test/test_copy_file.cpp @@ -35,6 +35,7 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/aux_/mmap.hpp" #include "libtorrent/aux_/open_mode.hpp" #include "test.hpp" +#include "test_utils.hpp" #include #include @@ -78,61 +79,6 @@ bool compare_files(std::string const& file1, std::string const& file2) return std::equal(it(f1), it{}, it(f2)); } -#if defined TORRENT_WINDOWS -bool fs_supports_sparse_files() -{ -#ifdef TORRENT_WINRT - HANDLE test = ::CreateFile2(L"test" - , GENERIC_WRITE - , FILE_SHARE_READ - , OPEN_ALWAYS - , nullptr); -#else - HANDLE test = ::CreateFileA("test" - , GENERIC_WRITE - , FILE_SHARE_READ - , nullptr - , OPEN_ALWAYS - , FILE_FLAG_SEQUENTIAL_SCAN - , nullptr); -#endif - TEST_CHECK(test != INVALID_HANDLE_VALUE); - DWORD fs_flags = 0; - wchar_t fs_name[50]; - TEST_CHECK(::GetVolumeInformationByHandleW(test, nullptr, 0, nullptr, nullptr - , &fs_flags, fs_name, sizeof(fs_name)) != 0); - ::CloseHandle(test); - printf("filesystem: %S\n", fs_name); - return (fs_flags & FILE_SUPPORTS_SPARSE_FILES) != 0; -} - -#else - -bool fs_supports_sparse_files() -{ - int test = ::open("test", O_RDWR | O_CREAT, 0755); - TEST_CHECK(test >= 0); - struct statfs st{}; - TEST_CHECK(fstatfs(test, &st) == 0); - ::close(test); -#ifdef TORRENT_LINUX - using fsword_t = decltype(statfs::f_type); - static fsword_t const ufs = 0x00011954; - static const std::set sparse_filesystems{ - EXT4_SUPER_MAGIC, EXT3_SUPER_MAGIC, XFS_SUPER_MAGIC, fsword_t(BTRFS_SUPER_MAGIC) - , ufs, REISERFS_SUPER_MAGIC, TMPFS_MAGIC, OVERLAYFS_SUPER_MAGIC - }; - printf("filesystem: %ld\n", long(st.f_type)); - return sparse_filesystems.count(st.f_type); -#else - printf("filesystem: (%d) %s\n", int(st.f_type), st.f_fstypename); - static const std::set sparse_filesystems{ - "ufs", "zfs", "ext4", "xfs", "apfs", "btrfs"}; - return sparse_filesystems.count(st.f_fstypename); -#endif -} - -#endif } TORRENT_TEST(basic) @@ -178,6 +124,7 @@ TORRENT_TEST(sparse_file) // Find out if the filesystem we're running the test on supports sparse // files. If not, we don't expect any of the files to be sparse bool const supports_sparse_files = fs_supports_sparse_files(); + printf("supports sparse files: %d\n", int(supports_sparse_files)); // make sure "sparse-1" is actually sparse #ifdef TORRENT_WINDOWS @@ -222,7 +169,7 @@ TORRENT_TEST(sparse_file) #else TEST_CHECK(::stat("sparse-1.copy", &st) == 0); printf("copy_size: %d\n", int(st.st_blocks) * 512); - TEST_EQUAL(st.st_blocks * 512, original_size); + TEST_CHECK(st.st_blocks * 512 < 500'000); #endif TEST_CHECK(compare_files("sparse-1", "sparse-1.copy")); diff --git a/test/test_storage.cpp b/test/test_storage.cpp index 519219f39bd..9cb83809532 100644 --- a/test/test_storage.cpp +++ b/test/test_storage.cpp @@ -566,6 +566,7 @@ void test_pre_allocate() std::string const test_path = complete("pre_allocate_test_path"); delete_dirs(combine_path(test_path, "temp_storage")); + bool const supports_prealloc = fs_supports_prealloc(); file_storage fs; std::vector buf; typename file_pool_type::type fp; @@ -630,7 +631,15 @@ void test_pre_allocate() TEST_CHECK(!ec); std::cerr << "error: " << ec.message() << std::endl; TEST_EQUAL(st.file_size, fs.file_size(i)); - TEST_CHECK(file_size_on_disk(path) >= fs.file_size(i)); + + if (supports_prealloc || fs.file_size(i) == 0) + { + TEST_CHECK(file_size_on_disk(path) >= fs.file_size(i)); + } + else + { + TEST_CHECK(file_size_on_disk(path) <= fs.file_size(i)); + } } } @@ -646,10 +655,17 @@ void test_pre_allocate() file_status st; std::string const path = fs.file_path(i, test_path); stat_file(path, &st, ec); - std::cerr<< "error: " << ec.message() << std::endl; + std::cerr << "error: " << ec.message() << std::endl; TEST_CHECK(!ec); - TEST_CHECK(file_size_on_disk(path) >= fs.file_size(i)); + if (supports_prealloc || fs.file_size(i) == 0) + { + TEST_CHECK(file_size_on_disk(path) >= fs.file_size(i)); + } + else + { + TEST_CHECK(file_size_on_disk(path) <= fs.file_size(i)); + } } } diff --git a/test/test_utils.cpp b/test/test_utils.cpp index 5e7e6da5ca0..84a57e26ba0 100644 --- a/test/test_utils.cpp +++ b/test/test_utils.cpp @@ -43,6 +43,15 @@ POSSIBILITY OF SUCH DAMAGE. #include // for _O_WRONLY #endif +#ifdef TORRENT_LINUX +#include +#include +#endif + +#ifndef TORRENT_WINDOWS +#include +#endif + namespace libtorrent { std::string time_now_string() @@ -147,3 +156,89 @@ lt::file_storage make_files(std::vector const files, int const piece_s return fs; } +#if defined TORRENT_WINDOWS +bool fs_supports_sparse_files() +{ +#ifdef TORRENT_WINRT + HANDLE test = ::CreateFile2(L"test" + , GENERIC_WRITE + , FILE_SHARE_READ + , OPEN_ALWAYS + , nullptr); +#else + HANDLE test = ::CreateFileA("test" + , GENERIC_WRITE + , FILE_SHARE_READ + , nullptr + , OPEN_ALWAYS + , FILE_FLAG_SEQUENTIAL_SCAN + , nullptr); +#endif + TEST_CHECK(test != INVALID_HANDLE_VALUE); + DWORD fs_flags = 0; + wchar_t fs_name[50]; + TEST_CHECK(::GetVolumeInformationByHandleW(test, nullptr, 0, nullptr, nullptr + , &fs_flags, fs_name, sizeof(fs_name)) != 0); + ::CloseHandle(test); + printf("filesystem: %S\n", fs_name); + return (fs_flags & FILE_SUPPORTS_SPARSE_FILES) != 0; +} + +#else + +bool fs_supports_sparse_files() +{ + int test = ::open("test", O_RDWR | O_CREAT, 0755); + TEST_CHECK(test >= 0); + struct statfs st{}; + TEST_CHECK(fstatfs(test, &st) == 0); + ::close(test); +#ifdef TORRENT_LINUX + using fsword_t = decltype(statfs::f_type); + static fsword_t const ufs = 0x00011954; + static fsword_t const zfs = 0x2fc12fc1; + static const std::set sparse_filesystems{ + EXT4_SUPER_MAGIC, EXT3_SUPER_MAGIC, XFS_SUPER_MAGIC, fsword_t(BTRFS_SUPER_MAGIC) + , ufs, zfs, REISERFS_SUPER_MAGIC, TMPFS_MAGIC, OVERLAYFS_SUPER_MAGIC + }; + printf("filesystem: %ld\n", long(st.f_type)); + return sparse_filesystems.count(st.f_type); +#else + printf("filesystem: (%d) %s\n", int(st.f_type), st.f_fstypename); + static const std::set sparse_filesystems{ + "ufs", "zfs", "ext4", "xfs", "apfs", "btrfs"}; + return sparse_filesystems.count(st.f_fstypename); +#endif +} + +#endif +bool fs_supports_prealloc() +{ +#ifdef TORRENT_WINDOWS + return true; +#else + int test = ::open("__test__", O_RDWR | O_CREAT, 0755); + TEST_CHECK(test >= 0); + struct statfs st{}; + TEST_CHECK(fstatfs(test, &st) == 0); + ::close(test); + // notably, ZFS does not support fallocate(). Even if glibc implements it to + // write zeroes, ZFS (when compression is enabled) will not write them to + // disk. +#ifdef TORRENT_LINUX + using fsword_t = decltype(statfs::f_type); + static fsword_t const ufs = 0x00011954; + static const std::set prealloc_filesystems{ + EXT4_SUPER_MAGIC, EXT3_SUPER_MAGIC, XFS_SUPER_MAGIC, fsword_t(BTRFS_SUPER_MAGIC) + , ufs, REISERFS_SUPER_MAGIC, TMPFS_MAGIC, OVERLAYFS_SUPER_MAGIC + }; + printf("filesystem: %ld\n", long(st.f_type)); + return prealloc_filesystems.count(st.f_type); +#else + printf("filesystem: (%d) %s\n", int(st.f_type), st.f_fstypename); + static const std::set prealloc_filesystems{ + "ufs", "ext4", "xfs", "apfs", "btrfs"}; + return prealloc_filesystems.count(st.f_fstypename); +#endif +#endif +} diff --git a/test/test_utils.hpp b/test/test_utils.hpp index 19d08ba19c6..0b3aed84525 100644 --- a/test/test_utils.hpp +++ b/test/test_utils.hpp @@ -66,6 +66,9 @@ EXPORT std::vector serialize(lt::torrent_info const& ti); EXPORT lt::aux::vector build_tree(int const size); +EXPORT bool fs_supports_sparse_files(); +EXPORT bool fs_supports_prealloc(); + #if defined _WIN32 && !defined TORRENT_MINGW int EXPORT truncate(char const* file, std::int64_t size); #endif