/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 | 0 | AutoFile::AutoFile(std::FILE* file, const Obfuscation& obfuscation) : m_file{file}, m_obfuscation{obfuscation} |
14 | 0 | { |
15 | 0 | if (!IsNull()) { |
16 | 0 | auto pos{std::ftell(m_file)}; |
17 | 0 | if (pos >= 0) m_position = pos; |
18 | 0 | } |
19 | 0 | } |
20 | | |
21 | | std::size_t AutoFile::detail_fread(std::span<std::byte> dst) |
22 | 0 | { |
23 | 0 | if (!m_file) throw std::ios_base::failure("AutoFile::read: file handle is nullptr"); |
24 | 0 | const size_t ret = std::fread(dst.data(), 1, dst.size(), m_file); |
25 | 0 | if (m_obfuscation) { |
26 | 0 | if (!m_position) throw std::ios_base::failure("AutoFile::read: position unknown"); |
27 | 0 | m_obfuscation(dst.subspan(0, ret), *m_position); |
28 | 0 | } |
29 | 0 | if (m_position) *m_position += ret; |
30 | 0 | return ret; |
31 | 0 | } |
32 | | |
33 | | void AutoFile::seek(int64_t offset, int origin) |
34 | 0 | { |
35 | 0 | if (IsNull()) { |
36 | 0 | throw std::ios_base::failure("AutoFile::seek: file handle is nullptr"); |
37 | 0 | } |
38 | 0 | 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 | 0 | if (origin == SEEK_SET) { |
42 | 0 | m_position = offset; |
43 | 0 | } else if (origin == SEEK_CUR && m_position.has_value()) { |
44 | 0 | *m_position += offset; |
45 | 0 | } else { |
46 | 0 | int64_t r{std::ftell(m_file)}; |
47 | 0 | if (r < 0) { |
48 | 0 | throw std::ios_base::failure("AutoFile::seek: ftell failed"); |
49 | 0 | } |
50 | 0 | m_position = r; |
51 | 0 | } |
52 | 0 | } |
53 | | |
54 | | int64_t AutoFile::tell() |
55 | 0 | { |
56 | 0 | if (!m_position.has_value()) throw std::ios_base::failure("AutoFile::tell: position unknown"); |
57 | 0 | return *m_position; |
58 | 0 | } |
59 | | |
60 | | int64_t AutoFile::size() |
61 | 0 | { |
62 | 0 | if (IsNull()) { |
63 | 0 | throw std::ios_base::failure("AutoFile::size: file handle is nullptr"); |
64 | 0 | } |
65 | | // Temporarily save the current position |
66 | 0 | int64_t current_pos = tell(); |
67 | 0 | seek(0, SEEK_END); |
68 | 0 | int64_t file_size = tell(); |
69 | | // Restore the original position |
70 | 0 | seek(current_pos, SEEK_SET); |
71 | 0 | return file_size; |
72 | 0 | } |
73 | | |
74 | | void AutoFile::read(std::span<std::byte> dst) |
75 | 0 | { |
76 | 0 | if (detail_fread(dst) != dst.size()) { |
77 | 0 | throw std::ios_base::failure(feof() ? "AutoFile::read: end of file" : "AutoFile::read: fread failed"); |
78 | 0 | } |
79 | 0 | } |
80 | | |
81 | | void AutoFile::ignore(size_t nSize) |
82 | 0 | { |
83 | 0 | if (!m_file) throw std::ios_base::failure("AutoFile::ignore: file handle is nullptr"); |
84 | 0 | unsigned char data[4096]; |
85 | 0 | while (nSize > 0) { |
86 | 0 | size_t nNow = std::min<size_t>(nSize, sizeof(data)); |
87 | 0 | if (std::fread(data, 1, nNow, m_file) != nNow) { |
88 | 0 | throw std::ios_base::failure(feof() ? "AutoFile::ignore: end of file" : "AutoFile::ignore: fread failed"); |
89 | 0 | } |
90 | 0 | nSize -= nNow; |
91 | 0 | if (m_position.has_value()) *m_position += nNow; |
92 | 0 | } |
93 | 0 | } |
94 | | |
95 | | void AutoFile::write(std::span<const std::byte> src) |
96 | 0 | { |
97 | 0 | if (!m_file) throw std::ios_base::failure("AutoFile::write: file handle is nullptr"); |
98 | 0 | if (!m_obfuscation) { |
99 | 0 | if (std::fwrite(src.data(), 1, src.size(), m_file) != src.size()) { |
100 | 0 | throw std::ios_base::failure("AutoFile::write: write failed"); |
101 | 0 | } |
102 | 0 | m_was_written = true; |
103 | 0 | if (m_position.has_value()) *m_position += src.size(); |
104 | 0 | } else { |
105 | 0 | std::array<std::byte, 4096> buf; |
106 | 0 | while (src.size()) { |
107 | 0 | auto buf_now{std::span{buf}.first(std::min<size_t>(src.size(), buf.size()))}; |
108 | 0 | std::copy_n(src.begin(), buf_now.size(), buf_now.begin()); |
109 | 0 | write_buffer(buf_now); |
110 | 0 | src = src.subspan(buf_now.size()); |
111 | 0 | } |
112 | 0 | } |
113 | 0 | } |
114 | | |
115 | | void AutoFile::write_buffer(std::span<std::byte> src) |
116 | 0 | { |
117 | 0 | if (!m_file) throw std::ios_base::failure("AutoFile::write_buffer: file handle is nullptr"); |
118 | 0 | if (m_obfuscation) { |
119 | 0 | if (!m_position) throw std::ios_base::failure("AutoFile::write_buffer: obfuscation position unknown"); |
120 | 0 | m_obfuscation(src, *m_position); // obfuscate in-place |
121 | 0 | } |
122 | 0 | if (std::fwrite(src.data(), 1, src.size(), m_file) != src.size()) { |
123 | 0 | throw std::ios_base::failure("AutoFile::write_buffer: write failed"); |
124 | 0 | } |
125 | 0 | m_was_written = true; |
126 | 0 | if (m_position) *m_position += src.size(); |
127 | 0 | } |
128 | | |
129 | | bool AutoFile::Commit() |
130 | 0 | { |
131 | 0 | return ::FileCommit(m_file); |
132 | 0 | } |
133 | | |
134 | | bool AutoFile::Truncate(unsigned size) |
135 | 0 | { |
136 | 0 | m_was_written = true; |
137 | 0 | return ::TruncateFile(m_file, size); |
138 | 0 | } |
139 | | |
140 | | size_t DataStream::GetMemoryUsage() const noexcept |
141 | 0 | { |
142 | 0 | return sizeof(*this) + memusage::DynamicUsage(vch); |
143 | 0 | } |