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