blob: 7aadfba92a8e44161cd42f21aaa5ccae536301b2 [file] [log] [blame]
Patrick Venture15f0f942020-07-09 09:38:18 -07001#include "sys_file_impl.hpp"
Kun Yi9125e632019-01-09 13:52:06 -08002
Willy Tu2b6683f2022-02-20 01:45:42 -08003#include <optional>
Kun Yi9125e632019-01-09 13:52:06 -08004#include <system_error>
5
6using namespace std::string_literals;
7
8static constexpr size_t rwBlockSize = 8192;
9
10namespace binstore
11{
12
13namespace
14{
15
16std::system_error errnoException(const std::string& message)
17{
18 return std::system_error(errno, std::generic_category(), message);
19}
20
21} // namespace
22
Willy Tu2b6683f2022-02-20 01:45:42 -080023SysFileImpl::SysFileImpl(const std::string& path, std::optional<size_t> offset,
Kun Yi9125e632019-01-09 13:52:06 -080024 const internal::Sys* sys) :
25 sys(sys)
26{
27 fd_ = sys->open(path.c_str(), O_RDWR);
Willy Tu62872f52022-02-24 15:53:42 -080028 offset_ = offset.value_or(0);
Kun Yi9125e632019-01-09 13:52:06 -080029
30 if (fd_ < 0)
31 {
32 throw errnoException("Error opening file "s + path);
33 }
34}
35
36SysFileImpl::~SysFileImpl()
37{
38 sys->close(fd_);
39}
40
41void SysFileImpl::lseek(size_t pos) const
42{
43 if (sys->lseek(fd_, offset_ + pos, SEEK_SET) < 0)
44 {
45 throw errnoException("Cannot lseek to pos "s + std::to_string(pos));
46 }
47}
48
49size_t SysFileImpl::readToBuf(size_t pos, size_t count, char* buf) const
50{
51
52 lseek(pos);
53
54 size_t bytesRead = 0;
55
56 do
57 {
58 auto ret = sys->read(fd_, &buf[bytesRead], count - bytesRead);
59 if (ret < 0)
60 {
61 if (errno == EINTR)
62 {
63 continue;
64 }
65
66 throw errnoException("Error reading from file"s);
67 }
68 else if (ret > 0)
69 {
70 bytesRead += ret;
71 }
72 else // ret == 0
73 {
74 break;
75 }
76 } while (bytesRead < count);
77
78 return bytesRead;
79}
80
81std::string SysFileImpl::readAsStr(size_t pos, size_t count) const
82{
83 std::string result;
Kun Yic83d2fa2019-04-03 18:40:19 -070084
85 /* If count is invalid, return an empty string. */
86 if (count == 0 || count > result.max_size())
87 {
88 return result;
89 }
90
Kun Yi9125e632019-01-09 13:52:06 -080091 result.resize(count);
92 size_t bytesRead = readToBuf(pos, count, result.data());
93 result.resize(bytesRead);
94 return result;
95}
96
97std::string SysFileImpl::readRemainingAsStr(size_t pos) const
98{
99 std::string result;
100 size_t bytesRead, size = 0;
101
102 /* Since we don't know how much to read, read 'rwBlockSize' at a time
103 * until there is nothing to read anymore. */
104 do
105 {
106 result.resize(size + rwBlockSize);
107 bytesRead = readToBuf(pos + size, rwBlockSize, result.data() + size);
108 size += bytesRead;
109 } while (bytesRead == rwBlockSize);
110
111 result.resize(size);
112 return result;
113}
114
115void SysFileImpl::writeStr(const std::string& data, size_t pos)
116{
117 lseek(pos);
118 ssize_t ret;
119 ret = sys->write(fd_, data.data(), data.size());
120 if (ret < 0)
121 {
122 throw errnoException("Error writing to file"s);
123 }
124 if (static_cast<size_t>(ret) != data.size())
125 {
126 throw std::runtime_error(
127 "Tried to send data size "s + std::to_string(data.size()) +
128 " but could only send "s + std::to_string(ret));
129 }
130}
131
132} // namespace binstore