Cogs.Core
FileHandle.Linux.cpp
1#include "FileHandle.h"
2
3#include "../StringView.h"
4
5#include "../Logging/Logger.h"
6
7#include <errno.h>
8#include <fcntl.h>
9#include <sys/mman.h>
10#include <sys/stat.h>
11#include <unistd.h>
12
13namespace {
14 Cogs::Logging::Log logger = Cogs::Logging::getLogger("FileHandle");
15}
16
17Cogs::FileHandle::~FileHandle() {
18 close();
19}
20
21Cogs::FileHandle::Ptr Cogs::FileHandle::open(std::string_view path, OpenMode openMode, AccessMode accessMode) {
22 Ptr handle = std::make_shared<FileHandle>();
23 int flags = 0;
24
25 if (accessMode == AccessMode::Read) {
26 flags = O_RDONLY;
27
28 if (openMode == OpenMode::OpenAlways) {
29 flags |= O_CREAT;
30 }
31 }
32 else {
33 flags = O_WRONLY;
34
35 switch (openMode) {
36 case OpenMode::Create: flags |= O_CREAT | O_EXCL; break;
37 case OpenMode::CreateAlways: flags |= O_CREAT | O_TRUNC; break;
38 case OpenMode::OpenAlways: flags |= O_CREAT; break;
39 case OpenMode::Open: break;
40 }
41 }
42
43 handle->fileDescriptor = ::open(std::string(path).c_str(), flags, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
44
45 if (handle->isOpen()) {
46 return handle;
47 }
48 LOG_ERROR(logger, "Failed to open %.*s. Error: %s.", StringViewFormat(path), strerror( errno ));
49 return nullptr;
50}
51
52void Cogs::FileHandle::close() {
53 if (isOpen()) {
54 ::close(fileDescriptor);
55 fileDescriptor = -1;
56 }
57}
58
59bool Cogs::FileHandle::isOpen() const {
60 return fileDescriptor != -1;
61}
62
63size_t Cogs::FileHandle::getSize() const {
64 if (isOpen()) {
65 struct stat buf = {};
66 int ret = ::fstat(fileDescriptor, &buf);
67 if(ret == -1){
68 LOG_ERROR(logger, "fstat error: %s.", strerror( errno ));
69 return 0;
70 }
71 return buf.st_size;
72 }
73 LOG_WARNING(logger, "Tried to query size of closed file.");
74 return 0;
75}
76
77bool Cogs::FileHandle::write(const void* ptr, size_t size, size_t& bytesWritten)
78{
79 const uint8_t* src = reinterpret_cast<const uint8_t*>(ptr);
80
81 bytesWritten = 0;
82
83 for (constexpr size_t limit = 0x7ffff000; size > limit; ) {
84 ssize_t justWritten = ::write(fileDescriptor, src, limit);
85
86 if (justWritten >= 0) {
87 bytesWritten += justWritten;
88 size -= justWritten;
89 src += justWritten;
90 }
91 else {
92 LOG_ERROR(logger, "Failed to write FileHandle %d. Error: %s.", fileDescriptor, strerror(errno));
93 return false;
94 }
95 }
96 if (size) {
97 ssize_t justWritten = ::write(fileDescriptor, src, size);
98
99 if (justWritten >= 0) {
100 bytesWritten += justWritten;
101 }
102 else {
103 LOG_ERROR(logger, "Failed to write FileHandle %d. Error: %s.", fileDescriptor, strerror(errno));
104 return false;
105 }
106 }
107 return true;
108}
109
110bool Cogs::FileHandle::read(void* buffer, size_t size, size_t& bytesRead)
111{
112 uint8_t* dest = reinterpret_cast<uint8_t*>(buffer);
113
114 bytesRead = 0;
115
116 for (constexpr size_t limit = 0x7ffff000; size > limit; ) {
117 ssize_t justRead = ::read(fileDescriptor, dest, limit);
118
119 if (justRead >= 0) {
120 dest += justRead;
121 size -= justRead;
122 bytesRead += justRead;
123 }
124 else {
125 LOG_ERROR(logger, "Failed to read FileHandle %d. Error: %s.", fileDescriptor, strerror(errno));
126 return false;
127 }
128 }
129 if (size) {
130 ssize_t justRead = ::read(fileDescriptor, dest, size);
131
132 if (justRead >= 0) {
133 bytesRead += justRead;
134 }
135 else {
136 LOG_ERROR(logger, "Failed to read FileHandle %d. Error: %s.", fileDescriptor, strerror(errno));
137 return false;
138 }
139 }
140 return true;
141}
142
143void* Cogs::FileHandle::map(ProtectionMode /*protectionMode*/, size_t offset, size_t size) {
144 if (isOpen()) {
145 if (!isMapped()) {
146 mappedMemory = ::mmap(nullptr, size, PROT_READ, MAP_SHARED, fileDescriptor, offset);
147
148 if (mappedMemory) {
149 mappedSize = size;
150 return mappedMemory;
151 }
152 else {
153 LOG_ERROR(logger, "Failed to map file into memory. Error: %s", strerror( errno ));
154 }
155 }
156 else {
157 LOG_ERROR(logger, "File handle cannot be mapped multiple times.");
158 }
159 }
160 else {
161 LOG_ERROR(logger, "Files must be opened before they can be memory mapped.");
162 }
163 return nullptr;
164}
165
166void Cogs::FileHandle::unmap() {
167 if (mappedMemory) {
168 ::munmap(mappedMemory, mappedSize);
169
170 mappedMemory = nullptr;
171 mappedSize = 0;
172 }
173}
Log implementation class.
Definition: LogManager.h:139
constexpr Log getLogger(const char(&name)[LEN]) noexcept
Definition: LogManager.h:180
@ Read
The buffer can be mapped and read from by the CPU after creation.
Definition: Flags.h:48