KittyIOFile.hpp
1 #pragma once 2 3 #include "KittyUtils.hpp" 4 5 #define KT_IO_BUFFER_SIZE ((size_t)(1024 * 1024)) 6 7 /** 8 * @brief This class provides an interface for file operations. 9 */ 10 class KittyIOFile 11 { 12 private: 13 int _fd; 14 std::string _filePath; 15 int _flags; 16 mode_t _mode; 17 int _error; 18 size_t _bufferSize; 19 20 public: 21 KittyIOFile() : _fd(-1), _flags(0), _mode(0), _error(0), _bufferSize(KT_IO_BUFFER_SIZE) 22 { 23 } 24 25 /** 26 * @brief Constructs a new KittyIOFile object with file path, flags, and mode. 27 * 28 * @param filePath The path to the file. 29 * @param flags The flags for opening the file. 30 * @param mode The mode for opening the file. 31 */ 32 KittyIOFile(const std::string &filePath, int flags, mode_t mode) 33 : _fd(-1), _filePath(filePath), _flags(flags), _mode(mode), _error(0), _bufferSize(KT_IO_BUFFER_SIZE) 34 { 35 } 36 37 /** 38 * @brief Constructs a new KittyIOFile object with file path and flags. 39 * 40 * @param filePath The path to the file. 41 * @param flags The flags for opening the file. 42 */ 43 KittyIOFile(const std::string &filePath, int flags) 44 : _fd(-1), _filePath(filePath), _flags(flags), _mode(0), _error(0), _bufferSize(KT_IO_BUFFER_SIZE) 45 { 46 } 47 48 ~KittyIOFile() 49 { 50 if (_fd >= 0) 51 { 52 ::close(_fd); 53 } 54 } 55 56 /** 57 * @brief Opens the file. 58 * 59 * @return true if the file was opened successfully, false otherwise. 60 */ 61 bool open(); 62 63 /** 64 * @brief Closes the file. 65 * 66 * @return true if the file was closed successfully, false otherwise. 67 */ 68 bool close(); 69 70 /** 71 * @brief Returns the last error. 72 * 73 * @return The last error code. 74 */ 75 inline int lastError() const 76 { 77 return _error; 78 } 79 80 /** 81 * @brief Returns the last error message. 82 * 83 * @return The last error message. 84 */ 85 inline std::string lastStrError() const 86 { 87 return _error ? strerror(_error) : ""; 88 } 89 90 /** 91 * @brief Returns the buffer size used for chunk reads/writes. 92 * 93 * @return The buffer size. 94 */ 95 inline size_t bufferSize() const 96 { 97 return _bufferSize; 98 } 99 100 /** 101 * @brief Sets the buffer size used for chunk reads/writes. 102 * 103 * @param size The new buffer size. 104 */ 105 inline void setBufferSize(size_t size) 106 { 107 _bufferSize = size; 108 } 109 110 /** 111 * @brief Returns the file descriptor. 112 * 113 * @return The file descriptor. 114 */ 115 inline int fd() const 116 { 117 return _fd; 118 } 119 120 /** 121 * @brief Returns the file path. 122 * 123 * @return The file path. 124 */ 125 inline std::string path() const 126 { 127 return _filePath; 128 } 129 130 /** 131 * @brief Returns the file flags. 132 * 133 * @return The file flags. 134 */ 135 inline int flags() const 136 { 137 return _flags; 138 } 139 140 /** 141 * @brief Returns the file mode. 142 * 143 * @return The file mode. 144 */ 145 inline mode_t mode() const 146 { 147 return _mode; 148 } 149 150 /** 151 * @brief Reads data from the file and advances file pointer. 152 * 153 * @param buffer The buffer to read into. 154 * @param len The number of bytes to read. 155 * @return The number of bytes read, or -1 on error. 156 */ 157 ssize_t read(void *buffer, size_t len); 158 159 /** 160 * @brief Writes data to the file and advances file pointer. 161 * 162 * @param buffer The buffer to write from. 163 * @param len The number of bytes to write. 164 * @return The number of bytes written, or -1 on error. 165 */ 166 ssize_t write(const void *buffer, size_t len); 167 168 /** 169 * @brief Reads data from the file at a given offset without changing file pointer. 170 * 171 * @param offset The offset to read from. 172 * @param buffer The buffer to read into. 173 * @param len The number of bytes to read. 174 * @return The number of bytes read, or -1 on error. 175 */ 176 ssize_t pread(uintptr_t offset, void *buffer, size_t len); 177 178 /** 179 * @brief Writes data to the file at a given offset without changing file pointer. 180 * 181 * @param offset The offset to write to. 182 * @param buffer The buffer to write from. 183 * @param len The number of bytes to write. 184 * @return The number of bytes written, or -1 on error. 185 */ 186 ssize_t pwrite(uintptr_t offset, const void *buffer, size_t len); 187 188 /** 189 * @brief Checks if the file exists. 190 * 191 * @return true if the file exists, false otherwise. 192 */ 193 inline bool exists() const 194 { 195 return access(_filePath.c_str(), F_OK) != -1; 196 } 197 198 /** 199 * @brief Checks if the file can be read. 200 * 201 * @return true if the file can be read, false otherwise. 202 */ 203 inline bool canRead() const 204 { 205 return access(_filePath.c_str(), R_OK) != -1; 206 } 207 208 /** 209 * @brief Checks if the file can be written. 210 * 211 * @return true if the file can be written, false otherwise. 212 */ 213 inline bool canWrite() const 214 { 215 return access(_filePath.c_str(), W_OK) != -1; 216 } 217 218 /** 219 * @brief Checks if the file can be executed. 220 * 221 * @return true if the file can be executed, false otherwise. 222 */ 223 inline bool canExecute() const 224 { 225 return access(_filePath.c_str(), X_OK) != -1; 226 } 227 228 /** 229 * @brief Removes the file. 230 * 231 * @return true if the file was removed successfully, false otherwise. 232 */ 233 inline bool remove() 234 { 235 _error = (unlink(_filePath.c_str()) == -1) ? errno : 0; 236 return _error == 0; 237 } 238 239 #ifdef __APPLE__ 240 /** 241 * @brief Retrieves information about the file. 242 * 243 * @return The file information. 244 */ 245 inline struct stat info() 246 { 247 struct stat s = {}; 248 _error = (stat(_filePath.c_str(), &s) == -1) ? errno : 0; 249 return s; 250 } 251 #else 252 /** 253 * @brief Retrieves information about the file. 254 * 255 * @return The file information. 256 */ 257 inline struct stat64 info() 258 { 259 struct stat64 s = {}; 260 _error = (stat64(_filePath.c_str(), &s) == -1) ? errno : 0; 261 return s; 262 } 263 #endif 264 265 /** 266 * @brief Checks if the file is a regular file. 267 * 268 * @return true if the file is a regular file, false otherwise. 269 */ 270 inline bool isFile() 271 { 272 auto s = info(); 273 return _error == 0 && S_ISREG(s.st_mode); 274 } 275 276 /** 277 * @brief Reads the contents of the file into a string. 278 * 279 * @param str The string to read into. 280 * @return true if the file was read successfully, false otherwise. 281 */ 282 bool readToString(std::string *str); 283 284 /** 285 * @brief Reads the contents of the file into a buffer. 286 * 287 * @param buf The buffer to read into. 288 * @return true if the file was read successfully, false otherwise. 289 */ 290 bool readToBuffer(std::vector<char> *buf); 291 292 /** 293 * @brief Writes the contents of the file at a given offset to another file. 294 * 295 * @param offset The offset to write to. 296 * @param len The number of bytes to write. 297 * @param filePath The file path to write to. 298 * @return true if the file was written successfully, false otherwise. 299 */ 300 bool writeOffsetToFile(uintptr_t offset, size_t len, const std::string &filePath); 301 302 /** 303 * @brief Writes the contents of the file to another file. 304 * 305 * @param filePath The file path to write to. 306 * @return true if the file was written successfully, false otherwise. 307 */ 308 bool writeToFile(const std::string &filePath) 309 { 310 KittyIOFile f(filePath, O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC, 0666); 311 return f.open() && writeToFd(f.fd()); 312 } 313 314 /** 315 * @brief Writes the contents of the file to a file descriptor. 316 * 317 * @param fd The file descriptor. 318 * @return true if the file was written successfully, false otherwise. 319 */ 320 bool writeToFd(int fd); 321 322 /** 323 * @brief Reads the contents of a file into a string. 324 * 325 * @param filePath The file path to read from. 326 * @param str The string to read into. 327 * @return true if the file was read successfully, false otherwise. 328 */ 329 inline static bool readFileToString(const std::string &filePath, std::string *str) 330 { 331 KittyIOFile f(filePath, O_RDONLY | O_CLOEXEC); 332 return f.open() && f.readToString(str); 333 } 334 335 /** 336 * @brief Reads the contents of a file into a buffer. 337 * 338 * @param filePath The file path to read from. 339 * @param buf The buffer to read into. 340 * @return true if the file was read successfully, false otherwise. 341 */ 342 inline static bool readFileToBuffer(const std::string &filePath, std::vector<char> *buf) 343 { 344 KittyIOFile f(filePath, O_RDONLY | O_CLOEXEC); 345 return f.open() && f.readToBuffer(buf); 346 } 347 348 /** 349 * @brief Copies the contents of a file to another file. 350 * 351 * @param srcFilePath The source file path. 352 * @param dstFilePath The destination file path. 353 * @return true if the file was copied successfully, false otherwise. 354 */ 355 inline static bool copy(const std::string &srcFilePath, const std::string &dstFilePath) 356 { 357 KittyIOFile f(srcFilePath, O_RDONLY | O_CLOEXEC); 358 return f.open() && f.writeToFile(dstFilePath); 359 } 360 361 /** 362 * @brief Lists files in a directory. 363 * 364 * @param dir The directory path. 365 * @param cb The callback function to be called for each file. 366 */ 367 static void listFilesCallback(const std::string &dir, std::function<bool(const std::string &)> cb); 368 369 /** 370 * @brief Recursively creates a directory path. 371 * 372 * This function creates all intermediate directories in the given path, 373 * similar to the behavior of `mkdir -p` on POSIX systems. 374 * 375 * @param path The full directory path to create (absolute or relative). 376 * @param mode The permissions to use when creating directories (default: 0755). 377 * 378 * @return true if the directory exists or was successfully created, 379 * false if an error occurred. 380 * 381 * @note If a directory already exists, it is not treated as an error. 382 * 383 * @warning This function does not verify whether an existing path component 384 * is a directory or a file. If a file exists in the path, creation 385 * will fail. 386 * 387 * 388 * @see mkdir(2) 389 */ 390 static bool createDirectoryRecursive(const std::string &path, mode_t mode = 0755); 391 };