KittyIOFile.cpp
1 #include "KittyIOFile.hpp" 2 3 bool KittyIOFile::open() 4 { 5 _error = 0; 6 if (_fd < 0) 7 { 8 if (_mode) 9 _fd = KT_EINTR_RETRY(::open(_filePath.c_str(), _flags, _mode)); 10 else 11 _fd = KT_EINTR_RETRY(::open(_filePath.c_str(), _flags)); 12 13 if (_fd < 0) 14 _error = errno; 15 } 16 return _fd >= 0; 17 } 18 19 bool KittyIOFile::close() 20 { 21 _error = 0; 22 if (_fd >= 0) 23 { 24 if (KT_EINTR_RETRY(::close(_fd)) == -1) 25 { 26 _error = errno; 27 return false; 28 } 29 _fd = -1; 30 } 31 return true; 32 } 33 34 ssize_t KittyIOFile::read(void *buffer, size_t len) 35 { 36 _error = 0; 37 38 if (_fd < 0) 39 return -1; 40 41 char *ptr = static_cast<char *>(buffer); 42 size_t total = 0; 43 while (total < len) 44 { 45 size_t toRead = std::min(len - total, _bufferSize); 46 ssize_t n = KT_EINTR_RETRY(::read(_fd, ptr + total, toRead)); 47 if (n <= 0) 48 { 49 _error = (n < 0) ? errno : 0; 50 return total > 0 ? total : -1; 51 } 52 total += n; 53 } 54 return total; 55 } 56 57 ssize_t KittyIOFile::write(const void *buffer, size_t len) 58 { 59 _error = 0; 60 61 if (_fd < 0) 62 return -1; 63 64 const char *ptr = static_cast<const char *>(buffer); 65 size_t total = 0; 66 while (total < len) 67 { 68 size_t toWrite = std::min(len - total, _bufferSize); 69 ssize_t n = KT_EINTR_RETRY(::write(_fd, ptr + total, toWrite)); 70 if (n <= 0) 71 { 72 _error = (n < 0) ? errno : 0; 73 return total > 0 ? total : -1; 74 } 75 total += n; 76 } 77 return total; 78 } 79 80 ssize_t KittyIOFile::pread(uintptr_t offset, void *buffer, size_t len) 81 { 82 _error = 0; 83 84 if (_fd < 0) 85 return -1; 86 87 char *ptr = static_cast<char *>(buffer); 88 size_t total = 0; 89 while (total < len) 90 { 91 size_t toRead = std::min(len - total, _bufferSize); 92 #ifdef __APPLE__ 93 ssize_t n = KT_EINTR_RETRY(::pread(_fd, ptr + total, toRead, (off_t)(offset + total))); 94 #else 95 ssize_t n = KT_EINTR_RETRY(::pread64(_fd, ptr + total, toRead, (off64_t)(offset + total))); 96 #endif 97 if (n <= 0) 98 { 99 _error = (n < 0) ? errno : 0; 100 return total > 0 ? total : -1; 101 } 102 total += n; 103 } 104 return total; 105 } 106 107 ssize_t KittyIOFile::pwrite(uintptr_t offset, const void *buffer, size_t len) 108 { 109 _error = 0; 110 111 if (_fd < 0) 112 return -1; 113 114 const char *ptr = static_cast<const char *>(buffer); 115 size_t total = 0; 116 while (total < len) 117 { 118 size_t toWrite = std::min(len - total, _bufferSize); 119 #ifdef __APPLE__ 120 ssize_t n = KT_EINTR_RETRY(::pwrite(_fd, ptr + total, toWrite, (off_t)(offset + total))); 121 #else 122 ssize_t n = KT_EINTR_RETRY(::pwrite64(_fd, ptr + total, toWrite, (off64_t)(offset + total))); 123 #endif 124 if (n <= 0) 125 { 126 _error = (n < 0) ? errno : 0; 127 return total > 0 ? total : -1; 128 } 129 total += n; 130 } 131 return total; 132 } 133 134 bool KittyIOFile::readToString(std::string *str) 135 { 136 _error = 0; 137 138 if (!str) 139 return false; 140 141 str->clear(); 142 143 auto s = info(); 144 if (_error == 0 && s.st_size > 0) 145 { 146 str->resize(s.st_size); 147 return (size_t)pread(0, str->data(), s.st_size) == (size_t)s.st_size; 148 } 149 150 std::vector<char> buffer(_bufferSize); 151 uintptr_t offset = 0; 152 while (true) 153 { 154 ssize_t n = pread(offset, buffer.data(), buffer.size()); 155 if (n <= 0) 156 break; 157 158 offset += n; 159 str->append(buffer.data(), n); 160 } 161 162 return _error == 0; 163 } 164 165 bool KittyIOFile::readToBuffer(std::vector<char> *buf) 166 { 167 _error = 0; 168 169 if (!buf) 170 return false; 171 172 buf->clear(); 173 174 auto s = info(); 175 if (_error == 0 && s.st_size > 0) 176 { 177 buf->resize(s.st_size); 178 return (size_t)pread(0, buf->data(), s.st_size) == (size_t)s.st_size; 179 } 180 181 std::vector<char> buffer(_bufferSize); 182 uintptr_t offset = 0; 183 while (true) 184 { 185 ssize_t n = pread(offset, buffer.data(), buffer.size()); 186 if (n <= 0) 187 break; 188 189 offset += n; 190 buf->insert(buf->end(), buffer.data(), buffer.data() + n); 191 } 192 193 return _error == 0; 194 } 195 196 bool KittyIOFile::writeOffsetToFile(uintptr_t offset, size_t len, const std::string &filePath) 197 { 198 _error = 0; 199 200 KittyIOFile of(filePath, O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC, 0666); 201 if (!of.open()) 202 return false; 203 204 std::vector<char> buffer(_bufferSize); 205 size_t remaining = len; 206 uintptr_t curr_off = offset; 207 208 while (remaining > 0) 209 { 210 size_t to_read = std::min(remaining, _bufferSize); 211 ssize_t nread = pread(curr_off, buffer.data(), to_read); 212 if (nread <= 0) 213 break; 214 215 if (of.write(buffer.data(), nread) != nread) 216 return false; 217 218 curr_off += nread; 219 remaining -= nread; 220 } 221 222 return remaining == 0; 223 } 224 225 bool KittyIOFile::writeToFd(int fd) 226 { 227 _error = 0; 228 229 if (_fd < 0 || fd < 0) 230 return false; 231 232 std::vector<char> buffer(_bufferSize); 233 uintptr_t offset = 0; 234 235 while (true) 236 { 237 ssize_t nr = pread(offset, buffer.data(), buffer.size()); 238 if (nr < 0) 239 return false; 240 241 if (nr == 0) 242 break; 243 244 ssize_t total_nw = 0; 245 while (total_nw < nr) 246 { 247 ssize_t nw = KT_EINTR_RETRY(::write(fd, buffer.data() + total_nw, nr - total_nw)); 248 if (nw <= 0) 249 { 250 _error = (nw < 0) ? errno : 0; 251 return false; 252 } 253 total_nw += nw; 254 } 255 256 offset += nr; 257 } 258 259 return true; 260 } 261 262 void KittyIOFile::listFilesCallback(const std::string &dirPath, std::function<bool(const std::string &)> cb) 263 { 264 DIR *dir = opendir(dirPath.c_str()); 265 if (!dir) 266 return; 267 268 std::string base = dirPath; 269 if (!base.empty() && base.back() != '/') 270 base += '/'; 271 272 while (struct dirent *f = readdir(dir)) 273 { 274 if (f->d_name[0] == '.') 275 continue; 276 277 std::string path = base + f->d_name; 278 if (f->d_type == DT_DIR) 279 { 280 listFilesCallback(path, cb); 281 } 282 else if (f->d_type == DT_REG) 283 { 284 if (cb && cb(path)) 285 break; 286 } 287 } 288 289 closedir(dir); 290 } 291 292 bool KittyIOFile::createDirectoryRecursive(const std::string &path, mode_t mode) 293 { 294 if (path.empty()) 295 return false; 296 297 std::string current; 298 size_t pos = 0; 299 300 // Handle absolute paths 301 if (path[0] == '/') 302 { 303 current = "/"; 304 pos = 1; 305 } 306 307 while (pos <= path.size()) 308 { 309 size_t next = path.find('/', pos); 310 std::string part = path.substr(pos, next - pos); 311 312 if (!part.empty()) 313 { 314 // Append next path component 315 if (!current.empty() && current.back() != '/') 316 current += "/"; 317 318 current += part; 319 320 // Attempt to create directory 321 if (mkdir(current.c_str(), mode) != 0) 322 { 323 if (errno != EEXIST) 324 { 325 return false; 326 } 327 } 328 } 329 330 if (next == std::string::npos) 331 break; 332 333 pos = next + 1; 334 } 335 336 return true; 337 }