blob: 2336af237d25640b8213f1a89fcedc24057b2399 [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;
83 result.resize(count);
84 size_t bytesRead = readToBuf(pos, count, result.data());
85 result.resize(bytesRead);
86 return result;
87}
88
89std::string SysFileImpl::readRemainingAsStr(size_t pos) const
90{
91 std::string result;
92 size_t bytesRead, size = 0;
93
94 /* Since we don't know how much to read, read 'rwBlockSize' at a time
95 * until there is nothing to read anymore. */
96 do
97 {
98 result.resize(size + rwBlockSize);
99 bytesRead = readToBuf(pos + size, rwBlockSize, result.data() + size);
100 size += bytesRead;
101 } while (bytesRead == rwBlockSize);
102
103 result.resize(size);
104 return result;
105}
106
107void SysFileImpl::writeStr(const std::string& data, size_t pos)
108{
109 lseek(pos);
110 ssize_t ret;
111 ret = sys->write(fd_, data.data(), data.size());
112 if (ret < 0)
113 {
114 throw errnoException("Error writing to file"s);
115 }
116 if (static_cast<size_t>(ret) != data.size())
117 {
118 throw std::runtime_error(
119 "Tried to send data size "s + std::to_string(data.size()) +
120 " but could only send "s + std::to_string(ret));
121 }
122}
123
124} // namespace binstore