/ deps / KittyMemoryEx / KittyIOFile.hpp
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  };