| Kun Yi | 9125e63 | 2019-01-09 13:52:06 -0800 | [diff] [blame] | 1 | #include "sys_file.hpp" | 
|  | 2 |  | 
|  | 3 | #include <system_error> | 
|  | 4 |  | 
|  | 5 | using namespace std::string_literals; | 
|  | 6 |  | 
|  | 7 | static constexpr size_t rwBlockSize = 8192; | 
|  | 8 |  | 
|  | 9 | namespace binstore | 
|  | 10 | { | 
|  | 11 |  | 
|  | 12 | namespace | 
|  | 13 | { | 
|  | 14 |  | 
|  | 15 | std::system_error errnoException(const std::string& message) | 
|  | 16 | { | 
|  | 17 | return std::system_error(errno, std::generic_category(), message); | 
|  | 18 | } | 
|  | 19 |  | 
|  | 20 | } // namespace | 
|  | 21 |  | 
|  | 22 | SysFileImpl::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 |  | 
|  | 35 | SysFileImpl::~SysFileImpl() | 
|  | 36 | { | 
|  | 37 | sys->close(fd_); | 
|  | 38 | } | 
|  | 39 |  | 
|  | 40 | void 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 |  | 
|  | 48 | size_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 |  | 
|  | 80 | std::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 |  | 
|  | 89 | std::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 |  | 
|  | 107 | void 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 |