F´ Flight Software - C/C++ Documentation devel
A framework for building embedded system applications to NASA flight quality standards.
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
FileStub.cpp
Go to the documentation of this file.
1#include <FpConfig.hpp>
2#include <Os/File.hpp>
3#include <Fw/Types/Assert.hpp>
5
6#include <cerrno>
7#include <sys/types.h>
8#include <sys/stat.h>
9#include <fcntl.h>
10#include <unistd.h>
11
12#include <cstring>
13#include <cstdio>
14
15namespace Os {
16
18 static void *readInterceptorPtr = nullptr;
19
21 static void *writeInterceptorPtr = nullptr;
22
24 static void *openInterceptorPtr = nullptr;
25
27 static void *seekInterceptorPtr = nullptr;
28
30
31 void registerReadInterceptor(ReadInterceptor funcPtr, void *ptr) {
32 readInterceptor = funcPtr;
34 }
35
37 readInterceptor = nullptr;
38 }
39
40 void registerWriteInterceptor(WriteInterceptor funcPtr, void *ptr) {
41 writeInterceptor = funcPtr;
43 }
44
46 writeInterceptor = nullptr;
47 }
48
49 void registerOpenInterceptor(OpenInterceptor funcPtr, void *ptr) {
50 openInterceptor = funcPtr;
52 }
53
55 openInterceptor = nullptr;
56 }
57
58 void registerSeekInterceptor(SeekInterceptor funcPtr, void *ptr) {
59 seekInterceptor = funcPtr;
61 }
62
64 seekInterceptor = nullptr;
65 }
66
68 lastError = error;
69 }
70
71
72 File::File() :m_fd(0),m_mode(OPEN_NO_MODE),m_lastError(0) {
73 }
74
75 File::~File() {
76 if (this->m_mode != OPEN_NO_MODE) {
77 this->close();
78 }
79 }
80
81 File::Status File::open(const char* fileName, File::Mode mode) {
82 return this->open(fileName, mode, true);
83 }
84
85 File::Status File::open(const char* fileName, File::Mode mode, bool include_excl) {
86
87 if (openInterceptor) {
88 File::Status stat;
89 if (not openInterceptor(stat,fileName,mode,openInterceptorPtr)) {
90 return stat;
91 }
92 }
93
94 NATIVE_INT_TYPE flags = 0;
95 Status stat = OP_OK;
96
97 switch (mode) {
98 case OPEN_READ:
99 flags = O_RDONLY;
100 break;
101 case OPEN_WRITE:
102 flags = O_WRONLY | O_CREAT | O_TRUNC;
103 break;
104 case OPEN_SYNC_WRITE:
105 flags = O_WRONLY | O_CREAT | O_SYNC;
106 break;
107 case OPEN_SYNC_DIRECT_WRITE:
108 flags = O_WRONLY | O_CREAT | O_DSYNC
109#ifdef __linux__
110 | O_DIRECT;
111#else
112 ;
113#endif
114 break;
115 case OPEN_CREATE:
116 flags = O_WRONLY | O_CREAT | O_TRUNC;
117 if(include_excl) {
118 flags |= O_EXCL;
119 }
120 break;
121 default:
122 FW_ASSERT(0,mode);
123 break;
124 }
125
126 NATIVE_INT_TYPE userFlags =
127#ifdef __VXWORKS__
128 0;
129#else
130 S_IRUSR|S_IWRITE;
131#endif
132 NATIVE_INT_TYPE fd = ::open(fileName,flags,userFlags);
133
134 if (-1 == fd) {
135 this->m_lastError = errno;
136 switch (errno) {
137 case ENOSPC:
138 stat = NO_SPACE;
139 break;
140 case ENOENT:
141 stat = DOESNT_EXIST;
142 break;
143 case EACCES:
144 stat = NO_PERMISSION;
145 break;
146 default:
147 stat = OTHER_ERROR;
148 break;
149 }
150 }
151
152 this->m_mode = mode;
153 this->m_fd = fd;
154 return stat;
155 }
156
157 File::Status File::prealloc(NATIVE_INT_TYPE offset, NATIVE_INT_TYPE len) {
158 // make sure it has been opened
159 if (OPEN_NO_MODE == this->m_mode) {
160 return NOT_OPENED;
161 }
162
163 File::Status fileStatus = OP_OK;
164
165#ifdef __linux__
166 NATIVE_INT_TYPE stat = posix_fallocate(this->m_fd, offset, len);
167
168 if (stat) {
169 switch (stat) {
170 case ENOSPC:
171 case EFBIG:
172 fileStatus = NO_SPACE;
173 break;
174 case EBADF:
175 fileStatus = DOESNT_EXIST;
176 break;
177 default:
178 fileStatus = OTHER_ERROR;
179 break;
180 }
181 }
182#endif
183
184 return fileStatus;
185 }
186
187 File::Status File::seek(NATIVE_INT_TYPE offset, bool absolute) {
188
189 if (seekInterceptor) {
190 File::Status stat;
191 if (not seekInterceptor(stat,offset,absolute,seekInterceptorPtr)) {
192 return stat;
193 }
194 }
195
196
197 // make sure it has been opened
198 if (OPEN_NO_MODE == this->m_mode) {
199 return NOT_OPENED;
200 }
201
202 Status stat = OP_OK;
203 NATIVE_INT_TYPE whence = absolute?SEEK_SET:SEEK_CUR;
204
205 off_t act_off = ::lseek(this->m_fd,offset,whence);
206
207 // No error would be a normal one for this simple
208 // class, so return other error
209 if (act_off != offset) {
210 if (-1 == act_off) {
211 this->m_lastError = errno;
212 stat = OTHER_ERROR;
213 } else {
214 stat = BAD_SIZE;
215 }
216 }
217
218 return stat;
219 }
220
221 File::Status File::read(void * buffer, NATIVE_INT_TYPE &size, bool waitForFull) {
222
223 FW_ASSERT(buffer);
224
225 if (readInterceptor) {
226 File::Status stat;
227 if (not readInterceptor(stat,buffer,size,waitForFull,readInterceptorPtr)) {
228 return stat;
229 }
230 }
231
232 // make sure it has been opened
233 if (OPEN_NO_MODE == this->m_mode) {
234 return NOT_OPENED;
235 }
236
237 NATIVE_INT_TYPE accSize = 0; // accumulated size
238
239 Status stat = OP_OK;
240
241 NATIVE_INT_TYPE maxIters = size*2; // loop limit; couldn't block more times than number of bytes
242
243 while (maxIters > 0) {
244
245 ssize_t readSize = ::read(this->m_fd,
246#ifdef __VXWORKS__
247 static_cast<char*>(buffer)
248#else
249 buffer
250#endif
251 ,size-accSize);
252
253 if (readSize != size-accSize) {
254 // could be an error
255 if (-1 == readSize) {
256 switch (errno) {
257 case EINTR: // read was interrupted
258 maxIters--; // decrement loop count
259 continue;
260 default:
261 stat = OTHER_ERROR;
262 break;
263 }
264 this->m_lastError = errno;
265 accSize = 0;
266 break; // break out of while loop
267 } else if (0 == readSize) { // end of file
268 accSize = 0;
269 break;
270 } else { // partial read so adjust read point and size
271 accSize += readSize;
272 if (not waitForFull) {
273 break; // break out of while loop
274 } else {
275 // in order to move the pointer ahead, we need to cast it
276 U8* charPtr = static_cast<U8*>(buffer);
277 charPtr = &charPtr[readSize];
278 buffer = static_cast<void*>(charPtr);
279 }
280 maxIters--; // decrement loop count
281 }
282
283 } else { // got number we wanted
284 accSize += readSize;
285 break; // break out of while loop
286 }
287
288 maxIters--; // decrement loop count
289
290 } // end read while loop
291
292 // make sure we didn't exceed loop count
293 FW_ASSERT(maxIters > 0);
294
295 size = accSize;
296
297 return stat;
298 }
299
300 File::Status File::write(const void * buffer, NATIVE_INT_TYPE &size, bool waitForDone) {
301
302 if (writeInterceptor) {
303 File::Status stat;
304 if (not writeInterceptor(stat,buffer,size,waitForDone,writeInterceptorPtr)) {
305 return stat;
306 }
307 }
308
309 // make sure it has been opened
310 if (OPEN_NO_MODE == this->m_mode) {
311 return NOT_OPENED;
312 }
313
314 Status stat = OP_OK;
315 // just check for EINTR
316 NATIVE_INT_TYPE maxIters = size*2; // loop limit; couldn't block more times than number of bytes
317 while (maxIters > 0) {
318 NATIVE_INT_TYPE writeSize = ::write(this->m_fd,
319#ifdef __VXWORKS__
320 static_cast<char*>(const_cast<void*>(buffer)) // Ugly, but that's how VxWorks likes to roll...
321#else
322 buffer
323#endif
324 ,size);
325 if (-1 == writeSize) {
326 switch (errno) {
327 case EINTR: // write was interrupted
328 maxIters--; // decrement loop count
329 continue;
330 case ENOSPC:
331 stat = NO_SPACE;
332 break;
333 default:
334 stat = OTHER_ERROR;
335 break;
336 }
337 this->m_lastError = errno;
338 break; // break out of while loop
339 } else {
340 size = writeSize;
341 break; // break out of while loop
342 }
343 }
344
345 return stat;
346 }
347
348 // NOTE(mereweth) - see http://lkml.iu.edu/hypermail/linux/kernel/1005.2/01845.html
349 // recommendation from Linus Torvalds, but doesn't seem to be that fast
350 File::Status File::bulkWrite(const void * buffer, NATIVE_UINT_TYPE &totalSize,
351 NATIVE_INT_TYPE chunkSize) {
352#ifdef __linux__
353 const NATIVE_UINT_TYPE startPosition = lseek(this->m_fd, 0, SEEK_CUR);
354#endif
355 NATIVE_UINT_TYPE newBytesWritten = 0;
356
357 for (NATIVE_UINT_TYPE idx = 0; idx < totalSize; idx += chunkSize) {
358 NATIVE_INT_TYPE size = chunkSize;
359 // if we're on the last iteration and length isn't a multiple of chunkSize
360 if (idx + chunkSize > totalSize) {
361 size = totalSize - idx;
362 }
363 const NATIVE_INT_TYPE toWrite = size;
364 const Os::File::Status fileStatus = this->write(buffer, size, false);
365 if (!(fileStatus == Os::File::OP_OK
366 && size == static_cast<NATIVE_INT_TYPE>(toWrite))) {
367 totalSize = newBytesWritten;
368 return fileStatus;
369 }
370
371#ifdef __linux__
372 sync_file_range(this->m_fd,
373 startPosition + newBytesWritten,
374 chunkSize,
375 SYNC_FILE_RANGE_WRITE);
376
377 if (newBytesWritten) {
378 sync_file_range(this->m_fd,
379 startPosition + newBytesWritten - chunkSize,
380 chunkSize,
381 SYNC_FILE_RANGE_WAIT_BEFORE
382 | SYNC_FILE_RANGE_WRITE
383 | SYNC_FILE_RANGE_WAIT_AFTER);
384 }
385#endif
386
387 newBytesWritten += toWrite;
388 }
389
390 totalSize = newBytesWritten;
391 return OP_OK;
392 }
393
394 File::Status File::flush() {
395 // make sure it has been opened
396 if (OPEN_NO_MODE == this->m_mode) {
397 return NOT_OPENED;
398 }
399
400 File::Status stat = OP_OK;
401
402 if (-1 == fsync(this->m_fd)) {
403 switch (errno) {
404 case ENOSPC:
405 stat = NO_SPACE;
406 break;
407 default:
408 stat = OTHER_ERROR;
409 break;
410 }
411 }
412
413 return stat;
414 }
415
416 void File::close() {
417 (void)::close(this->m_fd);
418 this->m_mode = OPEN_NO_MODE;
419 }
420
421 NATIVE_INT_TYPE File::getLastError() {
422 return lastError;
423 }
424
425 const char* File::getLastErrorString() {
426 return strerror(this->m_lastError);
427 }
428
429
430
431}
#define FW_ASSERT(...)
Definition Assert.hpp:14
PlatformIntType NATIVE_INT_TYPE
Definition BasicTypes.h:51
uint8_t U8
8-bit unsigned integer
Definition BasicTypes.h:26
PlatformUIntType NATIVE_UINT_TYPE
Definition BasicTypes.h:52
C++-compatible configuration header for fprime configuration.
File()
Constructor.
Definition File.cpp:8
@ OP_OK
Operation was successful.
Definition File.hpp:24
@ OP_OK
Operation was successful.
@ NO_PERMISSION
No permission to write.
@ OTHER_ERROR
other OS-specific error
@ NO_SPACE
No space left.
Definition File.cpp:6
void registerReadInterceptor(ReadInterceptor funcPtr, void *ptr)
Definition FileStub.cpp:31
bool(* OpenInterceptor)(Os::File::Status &status, const char *fileName, Os::File::Mode mode, void *ptr)
Definition FileStubs.hpp:24
static WriteInterceptor writeInterceptor
Definition FileStub.cpp:20
static void * readInterceptorPtr
Definition FileStub.cpp:18
static void * seekInterceptorPtr
Definition FileStub.cpp:27
static OpenInterceptor openInterceptor
Definition FileStub.cpp:23
void clearWriteInterceptor()
Definition FileStub.cpp:45
void clearSeekInterceptor()
Definition FileStub.cpp:63
static ReadInterceptor readInterceptor
Definition FileStub.cpp:17
void registerSeekInterceptor(SeekInterceptor funcPtr, void *ptr)
Definition FileStub.cpp:58
void setLastError(NATIVE_INT_TYPE error)
Definition FileStub.cpp:67
static NATIVE_INT_TYPE lastError
Definition FileStub.cpp:29
void registerWriteInterceptor(WriteInterceptor funcPtr, void *ptr)
Definition FileStub.cpp:40
static SeekInterceptor seekInterceptor
Definition FileStub.cpp:26
static void * openInterceptorPtr
Definition FileStub.cpp:24
static void * writeInterceptorPtr
Definition FileStub.cpp:21
bool(* WriteInterceptor)(Os::File::Status &status, const void *buffer, NATIVE_INT_TYPE &size, bool waitForDone, void *ptr)
Definition FileStubs.hpp:26
void registerOpenInterceptor(OpenInterceptor funcPtr, void *ptr)
Definition FileStub.cpp:49
bool(* SeekInterceptor)(Os::File::Status &status, NATIVE_INT_TYPE offset, bool absolute, void *ptr)
Definition FileStubs.hpp:27
void clearReadInterceptor()
Definition FileStub.cpp:36
void clearOpenInterceptor()
Definition FileStub.cpp:54
bool(* ReadInterceptor)(Os::File::Status &status, void *buffer, NATIVE_INT_TYPE &size, bool waitForFull, void *ptr)
Definition FileStubs.hpp:25