F´ Flight Software - C/C++ Documentation NASA-v1.6.0
A framework for building embedded system applications to NASA flight quality standards.
Loading...
Searching...
No Matches
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:7
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