CppCommon 1.0.5.0
C++ Common Library
Loading...
Searching...
No Matches
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
25namespace CppCommon {
26
28
29class File::Impl
30{
31 friend class File;
32
33public:
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;
146 if (permissions & FilePermissions::IRUSR)
147 mode |= S_IRUSR;
148 if (permissions & FilePermissions::IWUSR)
149 mode |= S_IWUSR;
150 if (permissions & FilePermissions::IXUSR)
151 mode |= S_IXUSR;
152 if (permissions & FilePermissions::IRGRP)
153 mode |= S_IRGRP;
154 if (permissions & FilePermissions::IWGRP)
155 mode |= S_IWGRP;
156 if (permissions & FilePermissions::IXGRP)
157 mode |= S_IXGRP;
158 if (permissions & FilePermissions::IROTH)
159 mode |= S_IROTH;
160 if (permissions & FilePermissions::IWOTH)
161 mode |= S_IWOTH;
162 if (permissions & FilePermissions::IXOTH)
163 mode |= S_IXOTH;
164 if (permissions & FilePermissions::ISUID)
165 mode |= S_ISUID;
166 if (permissions & FilePermissions::ISGID)
167 mode |= S_ISGID;
168 if (permissions & FilePermissions::ISVTX)
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;
176 if (attributes & FileAttributes::NORMAL)
177 dwFlagsAndAttributes |= FILE_ATTRIBUTE_NORMAL;
178 if (attributes & FileAttributes::ARCHIVED)
179 dwFlagsAndAttributes |= FILE_ATTRIBUTE_ARCHIVE;
180 if (attributes & FileAttributes::HIDDEN)
181 dwFlagsAndAttributes |= FILE_ATTRIBUTE_HIDDEN;
182 if (attributes & FileAttributes::INDEXED)
183 dwFlagsAndAttributes |= FILE_ATTRIBUTE_NOT_CONTENT_INDEXED;
184 if (attributes & FileAttributes::OFFLINE)
185 dwFlagsAndAttributes |= FILE_ATTRIBUTE_OFFLINE;
186 if (attributes & FileAttributes::READONLY)
187 dwFlagsAndAttributes |= FILE_ATTRIBUTE_READONLY;
188 if (attributes & FileAttributes::SYSTEM)
189 dwFlagsAndAttributes |= FILE_ATTRIBUTE_SYSTEM;
190 if (attributes & FileAttributes::TEMPORARY)
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;
220 if (permissions & FilePermissions::IRUSR)
221 mode |= S_IRUSR;
222 if (permissions & FilePermissions::IWUSR)
223 mode |= S_IWUSR;
224 if (permissions & FilePermissions::IXUSR)
225 mode |= S_IXUSR;
226 if (permissions & FilePermissions::IRGRP)
227 mode |= S_IRGRP;
228 if (permissions & FilePermissions::IWGRP)
229 mode |= S_IWGRP;
230 if (permissions & FilePermissions::IXGRP)
231 mode |= S_IXGRP;
232 if (permissions & FilePermissions::IROTH)
233 mode |= S_IROTH;
234 if (permissions & FilePermissions::IWOTH)
235 mode |= S_IWOTH;
236 if (permissions & FilePermissions::IXOTH)
237 mode |= S_IXOTH;
238 if (permissions & FilePermissions::ISUID)
239 mode |= S_ISUID;
240 if (permissions & FilePermissions::ISGID)
241 mode |= S_ISGID;
242 if (permissions & FilePermissions::ISVTX)
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;
250 if (attributes & FileAttributes::NORMAL)
251 dwFlagsAndAttributes |= FILE_ATTRIBUTE_NORMAL;
252 if (attributes & FileAttributes::ARCHIVED)
253 dwFlagsAndAttributes |= FILE_ATTRIBUTE_ARCHIVE;
254 if (attributes & FileAttributes::HIDDEN)
255 dwFlagsAndAttributes |= FILE_ATTRIBUTE_HIDDEN;
256 if (attributes & FileAttributes::INDEXED)
257 dwFlagsAndAttributes |= FILE_ATTRIBUTE_NOT_CONTENT_INDEXED;
258 if (attributes & FileAttributes::OFFLINE)
259 dwFlagsAndAttributes |= FILE_ATTRIBUTE_OFFLINE;
260 if (attributes & FileAttributes::READONLY)
261 dwFlagsAndAttributes |= FILE_ATTRIBUTE_READONLY;
262 if (attributes & FileAttributes::SYSTEM)
263 dwFlagsAndAttributes |= FILE_ATTRIBUTE_SYSTEM;
264 if (attributes & FileAttributes::TEMPORARY)
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;
294 if (permissions & FilePermissions::IRUSR)
295 mode |= S_IRUSR;
296 if (permissions & FilePermissions::IWUSR)
297 mode |= S_IWUSR;
298 if (permissions & FilePermissions::IXUSR)
299 mode |= S_IXUSR;
300 if (permissions & FilePermissions::IRGRP)
301 mode |= S_IRGRP;
302 if (permissions & FilePermissions::IWGRP)
303 mode |= S_IWGRP;
304 if (permissions & FilePermissions::IXGRP)
305 mode |= S_IXGRP;
306 if (permissions & FilePermissions::IROTH)
307 mode |= S_IROTH;
308 if (permissions & FilePermissions::IWOTH)
309 mode |= S_IWOTH;
310 if (permissions & FilePermissions::IXOTH)
311 mode |= S_IXOTH;
312 if (permissions & FilePermissions::ISUID)
313 mode |= S_ISUID;
314 if (permissions & FilePermissions::ISGID)
315 mode |= S_ISGID;
316 if (permissions & FilePermissions::ISVTX)
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;
324 if (attributes & FileAttributes::NORMAL)
325 dwFlagsAndAttributes |= FILE_ATTRIBUTE_NORMAL;
326 if (attributes & FileAttributes::ARCHIVED)
327 dwFlagsAndAttributes |= FILE_ATTRIBUTE_ARCHIVE;
328 if (attributes & FileAttributes::HIDDEN)
329 dwFlagsAndAttributes |= FILE_ATTRIBUTE_HIDDEN;
330 if (attributes & FileAttributes::INDEXED)
331 dwFlagsAndAttributes |= FILE_ATTRIBUTE_NOT_CONTENT_INDEXED;
332 if (attributes & FileAttributes::OFFLINE)
333 dwFlagsAndAttributes |= FILE_ATTRIBUTE_OFFLINE;
334 if (attributes & FileAttributes::READONLY)
335 dwFlagsAndAttributes |= FILE_ATTRIBUTE_READONLY;
336 if (attributes & FileAttributes::SYSTEM)
337 dwFlagsAndAttributes |= FILE_ATTRIBUTE_SYSTEM;
338 if (attributes & FileAttributes::TEMPORARY)
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
630private:
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
652const Flags<FileAttributes> File::DEFAULT_ATTRIBUTES = FileAttributes::NORMAL;
654const 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
667File::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
678File::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
689File::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
701{
702 File(file).swap(*this);
703 return *this;
704}
705
706File& File::operator=(File&& file) noexcept
707{
708 File(std::move(file)).swap(*this);
709 return *this;
710}
711
712uint64_t File::offset() const { return impl().offset(); }
713uint64_t File::size() const { return impl().size(); }
714
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
751bool File::IsFileOpened() const { return impl().IsFileOpened(); }
752bool File::IsFileReadOpened() const { return impl().IsFileReadOpened(); }
753bool File::IsFileWriteOpened() const { return impl().IsFileWriteOpened(); }
754
755void 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); }
756void 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); }
757void 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
759size_t File::Read(void* buffer, size_t size) { return impl().Read(buffer, size); }
760size_t File::Write(const void* buffer, size_t size) { return impl().Write(buffer, size); }
761
762void File::Seek(uint64_t offset) { return impl().Seek(offset); }
763void File::Resize(uint64_t size) { return impl().Resize(size); }
764void File::Flush() { impl().Flush(); }
765void File::Close() { impl().Close(); }
766
767std::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
776std::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
785std::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
794size_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
803size_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
812size_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
821void File::WriteEmpty(const Path& path)
822{
823 File temp(path);
824 temp.OpenOrCreate(false, true, true);
825 temp.Close();
826}
827
828void 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
friend void swap(File &file1, File &file2) noexcept
Definition file.inl:11
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
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
size_t Write(const void *buffer, size_t size) override
Write a byte buffer into the opened file.
Definition file.cpp:760
static const Flags< FileAttributes > DEFAULT_ATTRIBUTES
Default file attributes (Normal)
Definition file.h:31
File & operator=(const Path &path)
Definition file.h:48
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
Enum-based flags.
Definition flags.h:65
Filesystem path.
Definition path.h:90
friend void swap(Path &path1, Path &path2) noexcept
Definition path.inl:38
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
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
#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.
void swap(FileCache &cache1, FileCache &cache2) noexcept
Definition filecache.inl:23
@ IWUSR
Write permission bit for the owner of the file.
@ IRGRP
Read permission bit for the group owner of the file.
@ IRUSR
Read permission bit for the owner of the file.
@ IROTH
Read permission bit for other users.
Aligned storage validator definition.