/root/bitcoin/src/streams.cpp
Line | Count | Source |
1 | | // Copyright (c) 2009-present The Bitcoin Core developers |
2 | | // Distributed under the MIT software license, see the accompanying |
3 | | // file COPYING or https://opensource.org/license/mit/. |
4 | | |
5 | | #include <memusage.h> |
6 | | #include <span.h> |
7 | | #include <streams.h> |
8 | | #include <util/fs_helpers.h> |
9 | | #include <util/obfuscation.h> |
10 | | |
11 | | #include <array> |
12 | | |
13 | 242k | AutoFile::AutoFile(std::FILE* file, const Obfuscation& obfuscation) : m_file{file}, m_obfuscation{obfuscation} |
14 | 242k | { |
15 | 242k | if (!IsNull()) { |
16 | 230k | auto pos{std::ftell(m_file)}; |
17 | 230k | if (pos >= 0) m_position = pos; |
18 | 230k | } |
19 | 242k | } |
20 | | |
21 | | std::size_t AutoFile::detail_fread(std::span<std::byte> dst) |
22 | 19.3M | { |
23 | 19.3M | if (!m_file) throw std::ios_base::failure("AutoFile::read: file handle is nullptr"); |
24 | 19.3M | const size_t ret = std::fread(dst.data(), 1, dst.size(), m_file); |
25 | 19.3M | if (m_obfuscation) { |
26 | 360k | if (!m_position) throw std::ios_base::failure("AutoFile::read: position unknown"); |
27 | 360k | m_obfuscation(dst.subspan(0, ret), *m_position); |
28 | 360k | } |
29 | 19.3M | if (m_position) *m_position += ret; |
30 | 19.3M | return ret; |
31 | 19.3M | } |
32 | | |
33 | | void AutoFile::seek(int64_t offset, int origin) |
34 | 136 | { |
35 | 136 | if (IsNull()) { |
36 | 0 | throw std::ios_base::failure("AutoFile::seek: file handle is nullptr"); |
37 | 0 | } |
38 | 136 | if (std::fseek(m_file, offset, origin) != 0) { |
39 | 0 | throw std::ios_base::failure(feof() ? "AutoFile::seek: end of file" : "AutoFile::seek: fseek failed"); |
40 | 0 | } |
41 | 136 | if (origin == SEEK_SET) { |
42 | 63 | m_position = offset; |
43 | 73 | } else if (origin == SEEK_CUR && m_position.has_value()) { |
44 | 37 | *m_position += offset; |
45 | 37 | } else { |
46 | 36 | int64_t r{std::ftell(m_file)}; |
47 | 36 | if (r < 0) { |
48 | 0 | throw std::ios_base::failure("AutoFile::seek: ftell failed"); |
49 | 0 | } |
50 | 36 | m_position = r; |
51 | 36 | } |
52 | 136 | } |
53 | | |
54 | | int64_t AutoFile::tell() |
55 | 36 | { |
56 | 36 | if (!m_position.has_value()) throw std::ios_base::failure("AutoFile::tell: position unknown"); |
57 | 36 | return *m_position; |
58 | 36 | } |
59 | | |
60 | | void AutoFile::read(std::span<std::byte> dst) |
61 | 19.1M | { |
62 | 19.1M | if (detail_fread(dst) != dst.size()) { |
63 | 2.34k | throw std::ios_base::failure(feof() ? "AutoFile::read: end of file" : "AutoFile::read: fread failed"); |
64 | 2.34k | } |
65 | 19.1M | } |
66 | | |
67 | | void AutoFile::ignore(size_t nSize) |
68 | 847 | { |
69 | 847 | if (!m_file) throw std::ios_base::failure("AutoFile::ignore: file handle is nullptr"); |
70 | 753 | unsigned char data[4096]; |
71 | 2.28k | while (nSize > 0) { |
72 | 1.81k | size_t nNow = std::min<size_t>(nSize, sizeof(data)); |
73 | 1.81k | if (std::fread(data, 1, nNow, m_file) != nNow) { |
74 | 280 | throw std::ios_base::failure(feof() ? "AutoFile::ignore: end of file" : "AutoFile::ignore: fread failed"); |
75 | 280 | } |
76 | 1.53k | nSize -= nNow; |
77 | 1.53k | if (m_position.has_value()) *m_position += nNow; |
78 | 1.53k | } |
79 | 753 | } |
80 | | |
81 | | void AutoFile::write(std::span<const std::byte> src) |
82 | 834k | { |
83 | 834k | if (!m_file) throw std::ios_base::failure("AutoFile::write: file handle is nullptr"); |
84 | 833k | if (!m_obfuscation) { |
85 | 754k | if (std::fwrite(src.data(), 1, src.size(), m_file) != src.size()) { |
86 | 1.44k | throw std::ios_base::failure("AutoFile::write: write failed"); |
87 | 1.44k | } |
88 | 752k | m_was_written = true; |
89 | 752k | if (m_position.has_value()) *m_position += src.size(); |
90 | 752k | } else { |
91 | 79.7k | std::array<std::byte, 4096> buf; |
92 | 159k | while (src.size()) { |
93 | 79.6k | auto buf_now{std::span{buf}.first(std::min<size_t>(src.size(), buf.size()))}; |
94 | 79.6k | std::copy_n(src.begin(), buf_now.size(), buf_now.begin()); |
95 | 79.6k | write_buffer(buf_now); |
96 | 79.6k | src = src.subspan(buf_now.size()); |
97 | 79.6k | } |
98 | 79.7k | } |
99 | 833k | } |
100 | | |
101 | | void AutoFile::write_buffer(std::span<std::byte> src) |
102 | 298k | { |
103 | 298k | if (!m_file) throw std::ios_base::failure("AutoFile::write_buffer: file handle is nullptr"); |
104 | 298k | if (m_obfuscation) { |
105 | 298k | if (!m_position) throw std::ios_base::failure("AutoFile::write_buffer: obfuscation position unknown"); |
106 | 298k | m_obfuscation(src, *m_position); // obfuscate in-place |
107 | 298k | } |
108 | 298k | if (std::fwrite(src.data(), 1, src.size(), m_file) != src.size()) { |
109 | 180 | throw std::ios_base::failure("AutoFile::write_buffer: write failed"); |
110 | 180 | } |
111 | 298k | m_was_written = true; |
112 | 298k | if (m_position) *m_position += src.size(); |
113 | 298k | } |
114 | | |
115 | | bool AutoFile::Commit() |
116 | 0 | { |
117 | 0 | return ::FileCommit(m_file); |
118 | 0 | } |
119 | | |
120 | | bool AutoFile::Truncate(unsigned size) |
121 | 0 | { |
122 | 0 | m_was_written = true; |
123 | 0 | return ::TruncateFile(m_file, size); |
124 | 0 | } |
125 | | |
126 | | size_t DataStream::GetMemoryUsage() const noexcept |
127 | 149k | { |
128 | 149k | return sizeof(*this) + memusage::DynamicUsage(vch); |
129 | 149k | } |