Skip to content

Commit

Permalink
fix tests to work on linux ZFS
Browse files Browse the repository at this point in the history
  • Loading branch information
arvidn committed Oct 21, 2024
1 parent 07b2574 commit 24e658a
Show file tree
Hide file tree
Showing 4 changed files with 120 additions and 59 deletions.
59 changes: 3 additions & 56 deletions test/test_copy_file.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 <fstream>
#include <set>
Expand Down Expand Up @@ -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<fsword_t> 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<std::string> sparse_filesystems{
"ufs", "zfs", "ext4", "xfs", "apfs", "btrfs"};
return sparse_filesystems.count(st.f_fstypename);
#endif
}

#endif
}

TORRENT_TEST(basic)
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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"));
Expand Down
22 changes: 19 additions & 3 deletions test/test_storage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<char> buf;
typename file_pool_type<StorageType>::type fp;
Expand Down Expand Up @@ -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));
}
}
}

Expand All @@ -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));
}
}
}

Expand Down
95 changes: 95 additions & 0 deletions test/test_utils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,15 @@ POSSIBILITY OF SUCH DAMAGE.
#include <fcntl.h> // for _O_WRONLY
#endif

#ifdef TORRENT_LINUX
#include <sys/statfs.h>
#include <linux/magic.h>
#endif

#ifndef TORRENT_WINDOWS
#include <sys/mount.h>
#endif

namespace libtorrent
{
std::string time_now_string()
Expand Down Expand Up @@ -147,3 +156,89 @@ lt::file_storage make_files(std::vector<file_ent> 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<fsword_t> 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<std::string> 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<fsword_t> 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<std::string> prealloc_filesystems{
"ufs", "ext4", "xfs", "apfs", "btrfs"};
return prealloc_filesystems.count(st.f_fstypename);
#endif
#endif
}
3 changes: 3 additions & 0 deletions test/test_utils.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,9 @@ EXPORT std::vector<char> serialize(lt::torrent_info const& ti);

EXPORT lt::aux::vector<lt::sha256_hash> 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
Expand Down

0 comments on commit 24e658a

Please sign in to comment.