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