CppCommon  1.0.4.1
C++ Common Library
file.cpp
Go to the documentation of this file.
1 
9 #include "filesystem/file.h"
10 
11 #include "errors/fatal.h"
13 
14 #include <cassert>
15 #include <cstring>
16 
17 #if defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__)
18 #include <sys/stat.h>
19 #include <fcntl.h>
20 #include <unistd.h>
21 #elif defined(_WIN32) || defined(_WIN64)
22 #include <windows.h>
23 #endif
24 
25 namespace CppCommon {
26 
28 
29 class File::Impl
30 {
31  friend class File;
32 
33 public:
34  explicit Impl(const Path* path) : _path(path), _read(false), _read_index(0), _read_size(0), _read_buffer(), _write(false), _write_index(0), _write_size(0), _write_buffer()
35  {
36 #if defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__)
37  _file = -1;
38 #elif defined(_WIN32) || defined(_WIN64)
39  _file = INVALID_HANDLE_VALUE;
40 #endif
41  }
42 
43  ~Impl()
44  {
45  try
46  {
47  if (IsFileOpened())
48  Close();
49  }
50  catch (const FileSystemException& ex)
51  {
52  fatality(FileSystemException(ex.string()).Attach(path()));
53  }
54  }
55 
56  const Path& path() const { return *_path; }
57 
58  uint64_t offset() const
59  {
60  assert(IsFileOpened() && "File is not opened!");
61  if (!IsFileOpened())
62  throwex FileSystemException("File is not opened!").Attach(path());
63 #if defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__)
64  off_t result = lseek(_file, 0, SEEK_CUR);
65  if (result == (off_t)-1)
66  throwex FileSystemException("Cannot seek the file!").Attach(path());
67  return (uint64_t)result;
68 #elif defined(_WIN32) || defined(_WIN64)
69  LARGE_INTEGER seek;
70  LARGE_INTEGER result;
71  seek.QuadPart = 0;
72  if (!SetFilePointerEx(_file, seek, &result, FILE_CURRENT))
73  throwex FileSystemException("Cannot seek the file!").Attach(path());
74  return (uint64_t)result.QuadPart;
75 #endif
76  }
77 
78  uint64_t size() const
79  {
80 #if defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__)
81  if (IsFileOpened())
82  {
83  struct stat status;
84  int result = fstat(_file, &status);
85  if (result != 0)
86  throwex FileSystemException("Cannot get the current file size!").Attach(path());
87  return (uint64_t)status.st_size;
88  }
89  else
90  {
91  struct stat status;
92  int result = stat(path().string().c_str(), &status);
93  if (result != 0)
94  throwex FileSystemException("Cannot get the current file size!").Attach(path());
95  return (uint64_t)status.st_size;
96  }
97 #elif defined(_WIN32) || defined(_WIN64)
98  if (IsFileOpened())
99  {
100  LARGE_INTEGER result;
101  if (!GetFileSizeEx(_file, &result))
102  throwex FileSystemException("Cannot get the current file size!").Attach(path());
103  return (uint64_t)result.QuadPart;
104  }
105  else
106  {
107  WIN32_FILE_ATTRIBUTE_DATA fad;
108  if (!GetFileAttributesExW(path().wstring().c_str(), GetFileExInfoStandard, &fad))
109  throwex FileSystemException("Cannot get the current file size!").Attach(path());
110 
111  LARGE_INTEGER result;
112  result.HighPart = fad.nFileSizeHigh;
113  result.LowPart = fad.nFileSizeLow;
114  return (uint64_t)result.QuadPart;
115  }
116 #endif
117  }
118 
119  bool IsFileOpened() const
120  {
121 #if defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__)
122  return (_file >= 0);
123 #elif defined(_WIN32) || defined(_WIN64)
124  return (_file != INVALID_HANDLE_VALUE);
125 #endif
126  }
127 
128  bool IsFileReadOpened() const
129  {
130  return _read;
131  }
132 
133  bool IsFileWriteOpened() const
134  {
135  return _write;
136  }
137 
138  void Create(bool read, bool write, const Flags<FileAttributes>& attributes = File::DEFAULT_ATTRIBUTES, const Flags<FilePermissions>& permissions = File::DEFAULT_PERMISSIONS, size_t buffer = File::DEFAULT_BUFFER)
139  {
140  // Close previously opened file
141  assert(!IsFileOpened() && "File is already opened!");
142  if (IsFileOpened())
143  Close();
144 #if defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__)
145  mode_t mode = 0;
147  mode |= S_IRUSR;
149  mode |= S_IWUSR;
151  mode |= S_IXUSR;
153  mode |= S_IRGRP;
155  mode |= S_IWGRP;
157  mode |= S_IXGRP;
159  mode |= S_IROTH;
161  mode |= S_IWOTH;
163  mode |= S_IXOTH;
165  mode |= S_ISUID;
167  mode |= S_ISGID;
169  mode |= S_ISVTX;
170 
171  _file = open(path().string().c_str(), O_CREAT | O_EXCL | ((read && write) ? O_RDWR : (read ? O_RDONLY : (write ? O_WRONLY : 0))), mode);
172  if (_file < 0)
173  throwex FileSystemException("Cannot create a new file!").Attach(path());
174 #elif defined(_WIN32) || defined(_WIN64)
175  DWORD dwFlagsAndAttributes = 0;
177  dwFlagsAndAttributes |= FILE_ATTRIBUTE_NORMAL;
179  dwFlagsAndAttributes |= FILE_ATTRIBUTE_ARCHIVE;
181  dwFlagsAndAttributes |= FILE_ATTRIBUTE_HIDDEN;
183  dwFlagsAndAttributes |= FILE_ATTRIBUTE_NOT_CONTENT_INDEXED;
185  dwFlagsAndAttributes |= FILE_ATTRIBUTE_OFFLINE;
187  dwFlagsAndAttributes |= FILE_ATTRIBUTE_READONLY;
189  dwFlagsAndAttributes |= FILE_ATTRIBUTE_SYSTEM;
191  dwFlagsAndAttributes |= FILE_ATTRIBUTE_TEMPORARY;
192 
193  _file = CreateFileW(path().wstring().c_str(), (read ? GENERIC_READ : 0) | (write ? GENERIC_WRITE : 0), FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, nullptr, CREATE_NEW, dwFlagsAndAttributes, nullptr);
194  if (_file == INVALID_HANDLE_VALUE)
195  throwex FileSystemException("Cannot create a new file!").Attach(path());
196 #endif
197  // Initialize file read buffer
198  _read = read;
199  _read_index = 0;
200  _read_size = 0;
201  if (read)
202  _read_buffer.resize(buffer);
203 
204  // Initialize file write buffer
205  _write = write;
206  _write_index = 0;
207  _write_size = 0;
208  if (write)
209  _write_buffer.resize(buffer);
210  }
211 
212  void Open(bool read, bool write, bool truncate = false, const Flags<FileAttributes>& attributes = File::DEFAULT_ATTRIBUTES, const Flags<FilePermissions>& permissions = File::DEFAULT_PERMISSIONS, size_t buffer = File::DEFAULT_BUFFER)
213  {
214  // Close previously opened file
215  assert(!IsFileOpened() && "File is already opened!");
216  if (IsFileOpened())
217  Close();
218 #if defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__)
219  mode_t mode = 0;
221  mode |= S_IRUSR;
223  mode |= S_IWUSR;
225  mode |= S_IXUSR;
227  mode |= S_IRGRP;
229  mode |= S_IWGRP;
231  mode |= S_IXGRP;
233  mode |= S_IROTH;
235  mode |= S_IWOTH;
237  mode |= S_IXOTH;
239  mode |= S_ISUID;
241  mode |= S_ISGID;
243  mode |= S_ISVTX;
244 
245  _file = open(path().string().c_str(), ((read && write) ? O_RDWR : (read ? O_RDONLY : (write ? O_WRONLY : 0))) | (truncate ? O_TRUNC : 0), mode);
246  if (_file < 0)
247  throwex FileSystemException("Cannot create a new file!").Attach(path());
248 #elif defined(_WIN32) || defined(_WIN64)
249  DWORD dwFlagsAndAttributes = 0;
251  dwFlagsAndAttributes |= FILE_ATTRIBUTE_NORMAL;
253  dwFlagsAndAttributes |= FILE_ATTRIBUTE_ARCHIVE;
255  dwFlagsAndAttributes |= FILE_ATTRIBUTE_HIDDEN;
257  dwFlagsAndAttributes |= FILE_ATTRIBUTE_NOT_CONTENT_INDEXED;
259  dwFlagsAndAttributes |= FILE_ATTRIBUTE_OFFLINE;
261  dwFlagsAndAttributes |= FILE_ATTRIBUTE_READONLY;
263  dwFlagsAndAttributes |= FILE_ATTRIBUTE_SYSTEM;
265  dwFlagsAndAttributes |= FILE_ATTRIBUTE_TEMPORARY;
266 
267  _file = CreateFileW(path().wstring().c_str(), (read ? GENERIC_READ : 0) | (write ? GENERIC_WRITE : 0), FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, nullptr, (truncate ? TRUNCATE_EXISTING : OPEN_EXISTING), dwFlagsAndAttributes, nullptr);
268  if (_file == INVALID_HANDLE_VALUE)
269  throwex FileSystemException("Cannot open existing file!").Attach(path());
270 #endif
271  // Initialize file read buffer
272  _read = read;
273  _read_index = 0;
274  _read_size = 0;
275  if (read)
276  _read_buffer.resize(buffer);
277 
278  // Initialize file write buffer
279  _write = write;
280  _write_index = 0;
281  _write_size = 0;
282  if (write)
283  _write_buffer.resize(buffer);
284  }
285 
286  void OpenOrCreate(bool read, bool write, bool truncate = false, const Flags<FileAttributes>& attributes = File::DEFAULT_ATTRIBUTES, const Flags<FilePermissions>& permissions = File::DEFAULT_PERMISSIONS, size_t buffer = File::DEFAULT_BUFFER)
287  {
288  // Close previously opened file
289  assert(!IsFileOpened() && "File is already opened!");
290  if (IsFileOpened())
291  Close();
292 #if defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__)
293  mode_t mode = 0;
295  mode |= S_IRUSR;
297  mode |= S_IWUSR;
299  mode |= S_IXUSR;
301  mode |= S_IRGRP;
303  mode |= S_IWGRP;
305  mode |= S_IXGRP;
307  mode |= S_IROTH;
309  mode |= S_IWOTH;
311  mode |= S_IXOTH;
313  mode |= S_ISUID;
315  mode |= S_ISGID;
317  mode |= S_ISVTX;
318 
319  _file = open(path().string().c_str(), O_CREAT | ((read && write) ? O_RDWR : (read ? O_RDONLY : (write ? O_WRONLY : 0))) | (truncate ? O_TRUNC : 0), mode);
320  if (_file < 0)
321  throwex FileSystemException("Cannot create a new file!").Attach(path());
322 #elif defined(_WIN32) || defined(_WIN64)
323  DWORD dwFlagsAndAttributes = 0;
325  dwFlagsAndAttributes |= FILE_ATTRIBUTE_NORMAL;
327  dwFlagsAndAttributes |= FILE_ATTRIBUTE_ARCHIVE;
329  dwFlagsAndAttributes |= FILE_ATTRIBUTE_HIDDEN;
331  dwFlagsAndAttributes |= FILE_ATTRIBUTE_NOT_CONTENT_INDEXED;
333  dwFlagsAndAttributes |= FILE_ATTRIBUTE_OFFLINE;
335  dwFlagsAndAttributes |= FILE_ATTRIBUTE_READONLY;
337  dwFlagsAndAttributes |= FILE_ATTRIBUTE_SYSTEM;
339  dwFlagsAndAttributes |= FILE_ATTRIBUTE_TEMPORARY;
340 
341  _file = CreateFileW(path().wstring().c_str(), (read ? GENERIC_READ : 0) | (write ? GENERIC_WRITE : 0), FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, nullptr, (truncate ? CREATE_ALWAYS : OPEN_ALWAYS), dwFlagsAndAttributes, nullptr);
342  if (_file == INVALID_HANDLE_VALUE)
343  throwex FileSystemException("Cannot open existing file!").Attach(path());
344 #endif
345  // Initialize file read buffer
346  _read = read;
347  _read_index = 0;
348  _read_size = 0;
349  if (read)
350  _read_buffer.resize(buffer);
351 
352  // Initialize file write buffer
353  _write = write;
354  _write_index = 0;
355  _write_size = 0;
356  if (write)
357  _write_buffer.resize(buffer);
358  }
359 
360  size_t Read(void* buffer, size_t size)
361  {
362  if ((buffer == nullptr) || (size == 0))
363  return 0;
364 
365  assert(IsFileReadOpened() && "File is not opened for reading!");
366  if (!IsFileReadOpened())
367  throwex FileSystemException("File is not opened for reading!").Attach(path());
368 
369  // Read file with zero buffer
370  if (_read_buffer.empty())
371  {
372 #if defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__)
373  ssize_t result = read(_file, buffer, size);
374  if (result < 0)
375  throwex FileSystemException("Cannot read from the file!").Attach(path());
376  return (size_t)result;
377 #elif defined(_WIN32) || defined(_WIN64)
378  DWORD result;
379  if (!ReadFile(_file, buffer, (DWORD)size, &result, nullptr))
380  throwex FileSystemException("Cannot read from the file!").Attach(path());
381  return (size_t)result;
382 #endif
383  }
384 
385  uint8_t* bytes = (uint8_t*)buffer;
386  size_t counter = 0;
387 
388  while (size > 0)
389  {
390  // Update the local read buffer from the file
391  if (_read_index == _read_size)
392  {
393  _read_index = 0;
394 #if defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__)
395  ssize_t result = read(_file, _read_buffer.data(), _read_buffer.size());
396  if (result < 0)
397  throwex FileSystemException("Cannot read from the file!").Attach(path());
398  _read_size = (size_t)result;
399 #elif defined(_WIN32) || defined(_WIN64)
400  DWORD result;
401  if (!ReadFile(_file, _read_buffer.data(), (DWORD)_read_buffer.size(), &result, nullptr))
402  throwex FileSystemException("Cannot read from the file!").Attach(path());
403  _read_size = (size_t)result;
404 #endif
405  // Stop if the end of file was met
406  if (_read_size == 0)
407  break;
408  }
409 
410  // Read remaining data form the local read buffer
411  size_t remain = _read_size - _read_index;
412  size_t num = (size < remain) ? size : remain;
413  std::memcpy(bytes, _read_buffer.data() + _read_index, num);
414  counter += num;
415  _read_index += num;
416  bytes += num;
417  size -= num;
418  }
419 
420  return counter;
421  }
422 
423  size_t Write(const void* buffer, size_t size)
424  {
425  if ((buffer == nullptr) || (size == 0))
426  return 0;
427 
428  assert(IsFileWriteOpened() && "File is not opened for writing!");
429  if (!IsFileWriteOpened())
430  throwex FileSystemException("File is not opened for writing!").Attach(path());
431 
432  // Write file with zero buffer
433  if (_write_buffer.empty())
434  {
435 #if defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__)
436  ssize_t result = write(_file, buffer, size);
437  if (result < 0)
438  throwex FileSystemException("Cannot write into the file!").Attach(path());
439  return (size_t)result;
440 #elif defined(_WIN32) || defined(_WIN64)
441  DWORD result;
442  if (!WriteFile(_file, buffer, (DWORD)size, &result, nullptr))
443  throwex FileSystemException("Cannot write into the file!").Attach(path());
444  return (size_t)result;
445 #endif
446  }
447 
448  const uint8_t* bytes = (const uint8_t*)buffer;
449  size_t counter = 0;
450 
451  while (size > 0)
452  {
453  // Update the local read buffer from the file
454  if (_write_size == _write_buffer.size())
455  {
456 #if defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__)
457  ssize_t result = write(_file, _write_buffer.data() + _write_index, (_write_size - _write_index));
458  if (result < 0)
459  throwex FileSystemException("Cannot write into the file!").Attach(path());
460  _write_index += (size_t)result;
461 #elif defined(_WIN32) || defined(_WIN64)
462  DWORD result;
463  if (!WriteFile(_file, _write_buffer.data() + _write_index, (DWORD)(_write_size - _write_index), &result, nullptr))
464  throwex FileSystemException("Cannot write into the file!").Attach(path());
465  _write_index += (size_t)result;
466 #endif
467  // Stop if the buffer was not written completely
468  if (_write_index != _write_size)
469  break;
470 
471  // Reset the buffer cursor
472  _write_index = 0;
473  _write_size = 0;
474  }
475 
476  // Write remaining data into the local write buffer
477  size_t remain = _write_buffer.size() - _write_size;
478  size_t num = (size < remain) ? size : remain;
479  std::memcpy(_write_buffer.data() + _write_size, bytes, num);
480  counter += num;
481  _write_size += num;
482  bytes += num;
483  size -= num;
484  }
485 
486  return counter;
487  }
488 
489  void Seek(uint64_t offset)
490  {
491  assert(IsFileOpened() && "File is not opened!");
492  if (!IsFileOpened())
493  throwex FileSystemException("File is not opened!").Attach(path());
494  // Flush write buffers
495  if (IsFileWriteOpened())
496  FlushBuffer();
497  // Reset the read buffer cursor
498  _read_index = 0;
499  _read_size = 0;
500 #if defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__)
501  off_t result = lseek(_file, (off_t)offset, SEEK_SET);
502  if (result == (off_t)-1)
503  throwex FileSystemException("Cannot seek the file!").Attach(path());
504 #elif defined(_WIN32) || defined(_WIN64)
505  LARGE_INTEGER seek;
506  LARGE_INTEGER result;
507  seek.QuadPart = offset;
508  if (!SetFilePointerEx(_file, seek, &result, FILE_BEGIN))
509  throwex FileSystemException("Cannot seek the file!").Attach(path());
510 #endif
511  }
512 
513  void Resize(uint64_t size)
514  {
515 #if defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__)
516  if (IsFileOpened())
517  {
518  int result = ftruncate(_file, (off_t)size);
519  if (result != 0)
520  throwex FileSystemException("Cannot resize the current file!").Attach(path());
521  }
522  else
523  {
524  int result = truncate(path().string().c_str(), (off_t)size);
525  if (result != 0)
526  throwex FileSystemException("Cannot resize the current file!").Attach(path());
527  }
528 #elif defined(_WIN32) || defined(_WIN64)
529  if (IsFileOpened())
530  {
531  uint64_t current = offset();
532  Seek(size);
533  if (!SetEndOfFile(_file))
534  throwex FileSystemException("Cannot resize the current file!").Attach(path());
535  Seek((current < size) ? current : size);
536  }
537  else
538  {
539  OpenOrCreate(false, true);
540  Resize(size);
541  Close();
542  }
543 #endif
544  }
545 
546  void FlushBuffer()
547  {
548  assert(IsFileWriteOpened() && "File is not opened for writing!");
549  if (!IsFileWriteOpened())
550  throwex FileSystemException("File is not opened for writing!").Attach(path());
551 #if defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__)
552  // Force to write all buffered data
553  size_t remain = _write_size - _write_index;
554  if (remain > 0)
555  {
556  ssize_t result = write(_file, _write_buffer.data() + _write_index, (_write_size - _write_index));
557  if (result < 0)
558  throwex FileSystemException("Cannot write into the file during the flush operation!").Attach(path());
559  _write_index += (size_t)result;
560  if (_write_index != _write_size)
561  throwex FileSystemException("Cannot write all remaining data into the file during the flush operation!").Attach(path());
562 
563  // Reset the write buffer cursor
564  _write_index = 0;
565  _write_size = 0;
566  }
567 #elif defined(_WIN32) || defined(_WIN64)
568  // Force to write all buffered data
569  size_t remain = _write_size - _write_index;
570  if (remain > 0)
571  {
572  DWORD result;
573  if (!WriteFile(_file, _write_buffer.data() + _write_index, (DWORD)(_write_size - _write_index), &result, nullptr))
574  throwex FileSystemException("Cannot write into the file during the flush operation!").Attach(path());
575  _write_index += (size_t)result;
576  if (_write_index != _write_size)
577  throwex FileSystemException("Cannot write all remaining data into the file during the flush operation!").Attach(path());
578 
579  // Reset the write buffer cursor
580  _write_index = 0;
581  _write_size = 0;
582  }
583 #endif
584  }
585 
586  void Flush()
587  {
588  FlushBuffer();
589 #if defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__)
590  int result = fsync(_file);
591  if (result != 0)
592  throwex FileSystemException("Cannot flush the file buffers!").Attach(path());
593 #elif defined(_WIN32) || defined(_WIN64)
594  if (!FlushFileBuffers(_file))
595  throwex FileSystemException("Cannot flush the file buffers!").Attach(path());
596 #endif
597  }
598 
599  void Close()
600  {
601  assert(IsFileOpened() && "File is not opened!");
602  if (!IsFileOpened())
603  throwex FileSystemException("File is not opened!").Attach(path());
604  // Flush the file buffer if the file is opened for writing
605  if (IsFileWriteOpened())
606  FlushBuffer();
607 #if defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__)
608  int result = close(_file);
609  if (result != 0)
610  throwex FileSystemException("Cannot close the file descriptor!").Attach(path());
611  _file = -1;
612 #elif defined(_WIN32) || defined(_WIN64)
613  if (!CloseHandle(_file))
614  throwex FileSystemException("Cannot close the file handle!").Attach(path());
615  _file = INVALID_HANDLE_VALUE;
616 #endif
617  // Clear file read buffer
618  _read = false;
619  _read_index = 0;
620  _read_size = 0;
621  _read_buffer.clear();
622 
623  // Clear file write buffer
624  _write = false;
625  _write_index = 0;
626  _write_size = 0;
627  _write_buffer.clear();
628  }
629 
630 private:
631  const Path* _path;
632 #if defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__)
633  int _file;
634 #elif defined(_WIN32) || defined(_WIN64)
635  HANDLE _file;
636 #endif
637  // File read buffer
638  bool _read;
639  size_t _read_index;
640  size_t _read_size;
641  std::vector<uint8_t> _read_buffer;
642 
643  // File write buffer
644  bool _write;
645  size_t _write_index;
646  size_t _write_size;
647  std::vector<uint8_t> _write_buffer;
648 };
649 
651 
652 const Flags<FileAttributes> File::DEFAULT_ATTRIBUTES = FileAttributes::NORMAL;
654 const size_t File::DEFAULT_BUFFER = 8192;
655 
657 {
658  // Check implementation storage parameters
659  [[maybe_unused]] ValidateAlignedStorage<sizeof(Impl), alignof(Impl), StorageSize, StorageAlign> _;
660  static_assert((StorageSize >= sizeof(Impl)), "File::StorageSize must be increased!");
661  static_assert(((StorageAlign % alignof(Impl)) == 0), "File::StorageAlign must be adjusted!");
662 
663  // Create the implementation instance
664  new(&_storage)Impl(this);
665 }
666 
667 File::File(const Path& path) : Path(path)
668 {
669  // Check implementation storage parameters
670  [[maybe_unused]] ValidateAlignedStorage<sizeof(Impl), alignof(Impl), StorageSize, StorageAlign> _;
671  static_assert((StorageSize >= sizeof(Impl)), "File::StorageSize must be increased!");
672  static_assert(((StorageAlign % alignof(Impl)) == 0), "File::StorageAlign must be adjusted!");
673 
674  // Create the implementation instance
675  new(&_storage)Impl(this);
676 }
677 
678 File::File(const File& file) : Path(file)
679 {
680  // Check implementation storage parameters
681  [[maybe_unused]] ValidateAlignedStorage<sizeof(Impl), alignof(Impl), StorageSize, StorageAlign> _;
682  static_assert((StorageSize >= sizeof(Impl)), "File::StorageSize must be increased!");
683  static_assert(((StorageAlign % alignof(Impl)) == 0), "File::StorageAlign must be adjusted!");
684 
685  // Create the implementation instance
686  new(&_storage)Impl(this);
687 }
688 
689 File::File(File&& file) noexcept : File()
690 {
691  file.swap(*this);
692 }
693 
695 {
696  // Delete the implementation instance
697  reinterpret_cast<Impl*>(&_storage)->~Impl();
698 }
699 
700 File& File::operator=(const File& file)
701 {
702  File(file).swap(*this);
703  return *this;
704 }
705 
706 File& File::operator=(File&& file) noexcept
707 {
708  File(std::move(file)).swap(*this);
709  return *this;
710 }
711 
712 uint64_t File::offset() const { return impl().offset(); }
713 uint64_t File::size() const { return impl().size(); }
714 
715 bool File::IsFileExists() const
716 {
717 #if defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__)
718  struct stat status;
719  int result = stat(string().c_str(), &status);
720  if (result != 0)
721  {
722  if ((errno == ENOENT) || (errno == ENOTDIR))
723  return false;
724  else
725  throwex FileSystemException("Cannot get the status of the file!").Attach(*this);
726  }
727 
728  if (S_ISDIR(status.st_mode))
729  return false;
730  else if (S_ISREG(status.st_mode))
731  return true;
732  else if (S_ISBLK(status.st_mode))
733  return true;
734  else if (S_ISCHR(status.st_mode))
735  return true;
736  else if (S_ISFIFO(status.st_mode))
737  return true;
738  else if (S_ISSOCK(status.st_mode))
739  return true;
740  else
741  return true;
742 #elif defined(_WIN32) || defined(_WIN64)
743  DWORD attributes = GetFileAttributesW(wstring().c_str());
744  if (attributes == INVALID_FILE_ATTRIBUTES)
745  return false;
746 
747  return (attributes & FILE_ATTRIBUTE_DIRECTORY) == 0;
748 #endif
749 }
750 
751 bool File::IsFileOpened() const { return impl().IsFileOpened(); }
752 bool File::IsFileReadOpened() const { return impl().IsFileReadOpened(); }
753 bool File::IsFileWriteOpened() const { return impl().IsFileWriteOpened(); }
754 
755 void File::Create(bool read, bool write, const Flags<FileAttributes>& attributes, const Flags<FilePermissions>& permissions, size_t buffer) { return impl().Create(read, write, attributes, permissions, buffer); }
756 void File::Open(bool read, bool write, bool truncate, const Flags<FileAttributes>& attributes, const Flags<FilePermissions>& permissions, size_t buffer) { impl().Open(read, write, truncate, attributes, permissions, buffer); }
757 void File::OpenOrCreate(bool read, bool write, bool truncate, const Flags<FileAttributes>& attributes, const Flags<FilePermissions>& permissions, size_t buffer) { impl().OpenOrCreate(read, write, truncate, attributes, permissions, buffer); }
758 
759 size_t File::Read(void* buffer, size_t size) { return impl().Read(buffer, size); }
760 size_t File::Write(const void* buffer, size_t size) { return impl().Write(buffer, size); }
761 
762 void File::Seek(uint64_t offset) { return impl().Seek(offset); }
763 void File::Resize(uint64_t size) { return impl().Resize(size); }
764 void File::Flush() { impl().Flush(); }
765 void File::Close() { impl().Close(); }
766 
767 std::vector<uint8_t> File::ReadAllBytes(const Path& path)
768 {
769  File temp(path);
770  temp.Open(true, false);
771  std::vector<uint8_t> result = temp.ReadAllBytes();
772  temp.Close();
773  return result;
774 }
775 
776 std::string File::ReadAllText(const Path& path)
777 {
778  File temp(path);
779  temp.Open(true, false);
780  std::string result = temp.ReadAllText();
781  temp.Close();
782  return result;
783 }
784 
785 std::vector<std::string> File::ReadAllLines(const Path& path)
786 {
787  File temp(path);
788  temp.Open(true, false);
789  std::vector<std::string> result = temp.ReadAllLines();
790  temp.Close();
791  return result;
792 }
793 
794 size_t File::WriteAllBytes(const Path& path, const void* buffer, size_t size)
795 {
796  File temp(path);
797  temp.OpenOrCreate(false, true, true);
798  size_t result = temp.Write(buffer, size);
799  temp.Close();
800  return result;
801 }
802 
803 size_t File::WriteAllText(const Path& path, const std::string& text)
804 {
805  File temp(path);
806  temp.OpenOrCreate(false, true, true);
807  size_t result = temp.Write(text);
808  temp.Close();
809  return result;
810 }
811 
812 size_t File::WriteAllLines(const Path& path, const std::vector<std::string>& lines)
813 {
814  File temp(path);
815  temp.OpenOrCreate(false, true, true);
816  size_t result = temp.Write(lines);
817  temp.Close();
818  return result;
819 }
820 
821 void File::WriteEmpty(const Path& path)
822 {
823  File temp(path);
824  temp.OpenOrCreate(false, true, true);
825  temp.Close();
826 }
827 
828 void File::swap(File& file) noexcept
829 {
830  using std::swap;
831  Path::swap(file);
832  swap(_storage, file._storage);
833  swap(impl()._path, file.impl()._path);
834 }
835 
836 } // namespace CppCommon
Filesystem file.
Definition: file.h:28
void Close()
Close the file.
Definition: file.cpp:765
size_t Read(void *buffer, size_t size) override
Read a bytes buffer from the opened file.
Definition: file.cpp:759
static const Flags< FilePermissions > DEFAULT_PERMISSIONS
Default file permissions (IRUSR | IWUSR | IRGRP | IROTH)
Definition: file.h:33
void Resize(uint64_t size)
Resize the current file.
Definition: file.cpp:763
static size_t WriteAllLines(const Path &path, const std::vector< std::string > &lines)
Write text lines into the given file.
Definition: file.cpp:812
static size_t WriteAllText(const Path &path, const std::string &text)
Write a text string into the given file.
Definition: file.cpp:803
File()
Initialize file with an empty path.
Definition: file.cpp:656
void OpenOrCreate(bool read, bool write, bool truncate=false, const Flags< FileAttributes > &attributes=File::DEFAULT_ATTRIBUTES, const Flags< FilePermissions > &permissions=File::DEFAULT_PERMISSIONS, size_t buffer=File::DEFAULT_BUFFER)
Open or create file.
Definition: file.cpp:757
uint64_t size() const
Get the current file size.
Definition: file.cpp:713
bool IsFileReadOpened() const
Is the file opened for reading?
Definition: file.cpp:752
virtual ~File()
Definition: file.cpp:694
virtual size_t Write(const void *buffer, size_t size)=0
Write a byte buffer base method.
bool IsFileOpened() const
Is the file opened?
Definition: file.cpp:751
static const size_t DEFAULT_BUFFER
Default file buffer size (8192)
Definition: file.h:35
void Flush() override
Flush the file.
Definition: file.cpp:764
bool IsFileWriteOpened() const
Is the file opened for writing?
Definition: file.cpp:753
File & operator=(const Path &path)
Definition: file.h:48
void Create(bool read, bool write, const Flags< FileAttributes > &attributes=File::DEFAULT_ATTRIBUTES, const Flags< FilePermissions > &permissions=File::DEFAULT_PERMISSIONS, size_t buffer=File::DEFAULT_BUFFER)
Create a new file.
Definition: file.cpp:755
bool IsFileExists() const
Is the file exists?
Definition: file.cpp:715
void Open(bool read, bool write, bool truncate=false, const Flags< FileAttributes > &attributes=File::DEFAULT_ATTRIBUTES, const Flags< FilePermissions > &permissions=File::DEFAULT_PERMISSIONS, size_t buffer=File::DEFAULT_BUFFER)
Open an existing file.
Definition: file.cpp:756
std::vector< std::string > ReadAllLines()
Read all text lines.
Definition: reader.cpp:38
void Seek(uint64_t offset)
Seek into the opened file.
Definition: file.cpp:762
static const Flags< FileAttributes > DEFAULT_ATTRIBUTES
Default file attributes (Normal)
Definition: file.h:31
std::vector< uint8_t > ReadAllBytes()
Read all bytes.
Definition: reader.cpp:15
std::string ReadAllText()
Read all text.
Definition: reader.cpp:32
void swap(File &file) noexcept
Swap two instances.
Definition: file.cpp:828
static size_t WriteAllBytes(const Path &path, const void *buffer, size_t size)
Write a bytes buffer into the given file.
Definition: file.cpp:794
static void WriteEmpty(const Path &path)
Write an empty file.
Definition: file.cpp:821
uint64_t offset() const
Get the current read/write offset of the opened file.
Definition: file.cpp:712
File system exception.
Definition: exceptions.h:19
FileSystemException & Attach(const Path &path)
Attach the given path to the exception.
Definition: exceptions.h:33
Filesystem path.
Definition: path.h:90
std::wstring wstring() const
Get the path value as a wide string.
Definition: path.h:153
Flags< FileAttributes > attributes() const
Get the path file attributes.
Definition: path.cpp:472
Path()
Initialize path with an empty value.
Definition: path.h:93
void swap(Path &path) noexcept
Swap two instances.
Definition: path.inl:32
Flags< FilePermissions > permissions() const
Get the path file permissions.
Definition: path.cpp:499
static Path temp()
Get the temporary path of the process.
Definition: path.cpp:987
static Path current()
Get the current path of the process.
Definition: path.cpp:880
std::string _path
Path string.
Definition: path.h:376
#define throwex
Throw extended exception macro.
Definition: exceptions.h:23
Fatal abort execution definition.
#define fatality(...)
Fatal abort execution extended macro.
Definition: fatal.h:22
Filesystem file definition.
C++ Common project definitions.
Definition: token_bucket.h:15
void swap(FileCache &cache1, FileCache &cache2) noexcept
Definition: filecache.inl:23
@ IXOTH
Execute or search permission bit for other users.
@ IWUSR
Write permission bit for the owner of the file.
@ IWGRP
Write permission bit for the group owner of the file.
@ IXUSR
Execute (for ordinary files) or search (for directories) permission bit for the owner of the file.
@ ISVTX
This is the sticky bit.
@ IRGRP
Read permission bit for the group owner of the file.
@ IRUSR
Read permission bit for the owner of the file.
@ IXGRP
Execute or search permission bit for the group owner of the file.
@ IWOTH
Write permission bit for other users.
@ IROTH
Read permission bit for other users.
@ ISUID
This is the set-user-ID on execute bit.
@ ISGID
This is the set-group-ID on execute bit.
Aligned storage validator definition.