Skip to content
API Documentation
BastionGuard™
disk_reader.cpp
Go to the documentation of this file.
1#include "disk_reader.hpp"
2#include "i18n.hpp"
3
4#include <cerrno>
5#include <cstring>
6
7#include <fcntl.h>
8#include <sys/stat.h>
9#include <sys/types.h>
10#include <unistd.h>
11
12#ifdef __linux__
13#include <linux/fs.h>
14#include <sys/ioctl.h>
15#endif
16
22
26
28 if (fd_ >= 0) {
29 ::close(fd_);
30 fd_ = -1;
31 }
32 is_block_device_ = false;
33 size_ = 0;
35 path_.clear();
36}
37
38bool DiskReader::open_readonly(const std::string& path, std::string& error) {
39 close();
40
41 struct stat st {};
42 if (::stat(path.c_str(), &st) != 0) {
43 error = std::string("stat failed: ") + std::strerror(errno);
44 return false;
45 }
46
47 if (!S_ISREG(st.st_mode) && !S_ISBLK(st.st_mode)) {
48 error = trs("source is neither a regular file nor a block device");
49 return false;
50 }
51
52 fd_ = ::open(path.c_str(), O_RDONLY | O_CLOEXEC);
53 if (fd_ < 0) {
54 error = std::string("open failed: ") + std::strerror(errno);
55 return false;
56 }
57
58 path_ = path;
59 is_block_device_ = S_ISBLK(st.st_mode);
60
61 if (is_block_device_) {
62 #ifdef __linux__
63 unsigned long long bytes = 0;
64 if (::ioctl(fd_, BLKGETSIZE64, &bytes) != 0) {
65 error = std::string("BLKGETSIZE64 failed: ") + std::strerror(errno);
66 close();
67 return false;
68 }
69 size_ = static_cast<uint64_t>(bytes);
70
71 unsigned int sector = 512;
72 if (::ioctl(fd_, BLKSSZGET, &sector) == 0 && sector > 0) {
73 logical_sector_size_ = sector;
74 }
75 #else
76 error = trs("block-device support is Linux-only in this build");
77 close();
78 return false;
79 #endif
80 } else {
81 size_ = static_cast<uint64_t>(st.st_size);
83 }
84
85 return true;
86}
87
88bool DiskReader::is_open() const {
89 return fd_ >= 0;
90}
91
93 return is_block_device_;
94}
95
96uint64_t DiskReader::size() const {
97 return size_;
98}
99
102}
103
104const std::string& DiskReader::path() const {
105 return path_;
106}
107
108bool DiskReader::read_at(uint64_t offset, void* buffer, size_t len) {
109 if (fd_ < 0 || buffer == nullptr) return false;
110 if (len == 0) return true;
111 // Bug #1 fix: avoid uint64_t overflow on offset + len
112 if (offset > size_ || len > size_ - offset) return false;
113
114 auto* ptr = static_cast<unsigned char*>(buffer);
115 size_t done = 0;
116
117 while (done < len) {
118 const auto n = ::pread(fd_, ptr + done, len - done, static_cast<off_t>(offset + done));
119 if (n <= 0) {
120 return false;
121 }
122 done += static_cast<size_t>(n);
123 }
124
125 return true;
126}
127
128std::vector<std::byte> DiskReader::read_block(uint64_t offset, size_t len) {
129 std::vector<std::byte> out(len);
130 if (!read_at(offset, out.data(), len)) {
131 out.clear();
132 }
133 return out;
134}
bool is_block_device_
bool is_block_device() const
bool is_open() const
std::vector< std::byte > read_block(uint64_t offset, size_t len)
uint32_t logical_sector_size() const
const std::string & path() const
bool read_at(uint64_t offset, void *buffer, size_t len)
bool open_readonly(const std::string &path, std::string &error)
uint64_t size_
uint32_t logical_sector_size_
uint64_t size() const
std::string path_
std::string trs(const char *msgid)
Definition i18n.cpp:22