1 | //===----------------------------------------------------------------------===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | |
9 | // UNSUPPORTED: c++03, c++11, c++14 |
10 | // REQUIRES: long_tests |
11 | // UNSUPPORTED: no-filesystem |
12 | // UNSUPPORTED: availability-filesystem-missing |
13 | |
14 | // <filesystem> |
15 | |
16 | // bool copy_file(const path& from, const path& to); |
17 | // bool copy_file(const path& from, const path& to, error_code& ec) noexcept; |
18 | // bool copy_file(const path& from, const path& to, copy_options options); |
19 | // bool copy_file(const path& from, const path& to, copy_options options, |
20 | // error_code& ec) noexcept; |
21 | |
22 | #include <filesystem> |
23 | #include <cassert> |
24 | #include <cstdio> |
25 | #include <string> |
26 | |
27 | #include "test_macros.h" |
28 | #include "filesystem_test_helper.h" |
29 | namespace fs = std::filesystem; |
30 | using namespace fs; |
31 | |
32 | // This test is intended to test 'sendfile's 2gb limit for a single call, and |
33 | // to ensure that libc++ correctly copies files larger than that limit. |
34 | // However it requires allocating ~5GB of filesystem space. This might not |
35 | // be acceptable on all systems. |
36 | static void large_file() { |
37 | using namespace fs; |
38 | constexpr std::uintmax_t sendfile_size_limit = 2147479552ull; |
39 | constexpr std::uintmax_t additional_size = 1024; |
40 | constexpr std::uintmax_t test_file_size = sendfile_size_limit + additional_size; |
41 | static_assert(test_file_size > sendfile_size_limit, "" ); |
42 | |
43 | scoped_test_env env; |
44 | |
45 | // Check that we have more than sufficient room to create the files needed |
46 | // to perform the test. |
47 | if (space(env.test_root).available < 3 * test_file_size) { |
48 | return; |
49 | } |
50 | |
51 | // Create a file right at the size limit. The file is full of '\0's. |
52 | const path source = env.create_file("source" , sendfile_size_limit); |
53 | const std::string additional_data(additional_size, 'x'); |
54 | // Append known data to the end of the source file. |
55 | { |
56 | std::FILE* outf = std::fopen(filename: source.string().c_str(), modes: "a" ); |
57 | assert(outf != nullptr); |
58 | std::fputs(s: additional_data.c_str(), stream: outf); |
59 | std::fclose(stream: outf); |
60 | } |
61 | assert(file_size(source) == test_file_size); |
62 | const path dest = env.make_env_path("dest" ); |
63 | |
64 | std::error_code ec = GetTestEC(); |
65 | assert(copy_file(source, dest, ec)); |
66 | assert(!ec); |
67 | |
68 | assert(is_regular_file(dest)); |
69 | assert(file_size(dest) == test_file_size); |
70 | |
71 | // Read the data from the end of the destination file, and ensure it matches |
72 | // the data at the end of the source file. |
73 | std::string out_data(additional_size, 'z'); |
74 | { |
75 | std::FILE* dest_file = std::fopen(filename: dest.string().c_str(), modes: "r" ); |
76 | assert(dest_file != nullptr); |
77 | assert(std::fseek(dest_file, sendfile_size_limit, SEEK_SET) == 0); |
78 | assert(std::fread(&out_data[0], sizeof(out_data[0]), additional_size, dest_file) == additional_size); |
79 | std::fclose(stream: dest_file); |
80 | } |
81 | assert(out_data.size() == additional_data.size()); |
82 | assert(out_data == additional_data); |
83 | } |
84 | |
85 | int main(int, char**) { |
86 | large_file(); |
87 | |
88 | return 0; |
89 | } |
90 | |