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