F´ Flight Software - C/C++ Documentation NASA-v1.6.0
A framework for building embedded system applications to NASA flight quality standards.
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
File.cpp
Go to the documentation of this file.
1#include <FpConfig.hpp>
2#include <Os/File.hpp>
3#include <Fw/Types/Assert.hpp>
4
5#ifdef __cplusplus
6extern "C" {
7#endif // __cplusplus
8
9#include <Utils/Hash/libcrc/lib_crc.h> // borrow CRC
10
11#ifdef __cplusplus
12}
13#endif // __cplusplus
14
15#include <cerrno>
16#include <sys/types.h>
17#include <sys/stat.h>
18#include <fcntl.h>
19#include <unistd.h>
20#include <limits>
21#include <cstring>
22#include <cstdio>
23
24//#define DEBUG_PRINT(x,...) printf(x,##__VA_ARGS__); fflush(stdout)
25#define DEBUG_PRINT(x,...)
26
27namespace Os {
28
29 File::File() :m_fd(-1),m_mode(OPEN_NO_MODE),m_lastError(0) {
30 }
31
32 File::~File() {
33 if (this->m_mode != OPEN_NO_MODE) {
34 this->close();
35 }
36 }
37
38 File::Status File::open(const char* fileName, File::Mode mode) {
39 return this->open(fileName, mode, true);
40 }
41 File::Status File::open(const char* fileName, File::Mode mode, bool include_excl) {
42
43 NATIVE_INT_TYPE flags = 0;
44 Status stat = OP_OK;
45
46 switch (mode) {
47 case OPEN_READ:
48 flags = O_RDONLY;
49 break;
50 case OPEN_WRITE:
51 flags = O_WRONLY | O_CREAT;
52 break;
53 case OPEN_SYNC_WRITE:
54 flags = O_WRONLY | O_CREAT | O_SYNC;
55 break;
56#ifndef TGT_OS_TYPE_RTEMS
58 flags = O_WRONLY | O_CREAT | O_DSYNC
59#ifdef __linux__
60 | O_DIRECT;
61#else
62 ;
63#endif
64 break;
65#endif
66 case OPEN_CREATE:
67 flags = O_WRONLY | O_CREAT | O_TRUNC;
68 if(include_excl) {
69 flags |= O_EXCL;
70 }
71 break;
72 case OPEN_APPEND:
73 flags = O_WRONLY | O_CREAT | O_APPEND;
74 break;
75 default:
76 FW_ASSERT(0, mode);
77 break;
78 }
79
80 NATIVE_INT_TYPE userFlags =
81#ifdef __VXWORKS__
82 0;
83#else
84 S_IRUSR|S_IWRITE;
85#endif
86 NATIVE_INT_TYPE fd = ::open(fileName,flags,userFlags);
87
88 if (-1 == fd) {
89 this->m_lastError = errno;
90 switch (errno) {
91 case ENOSPC:
92 stat = NO_SPACE;
93 break;
94 case ENOENT:
95 stat = DOESNT_EXIST;
96 break;
97 case EACCES:
98 stat = NO_PERMISSION;
99 break;
100 case EEXIST:
101 stat = FILE_EXISTS;
102 break;
103 default:
104 stat = OTHER_ERROR;
105 break;
106 }
107 }
108
109 this->m_mode = mode;
110 this->m_fd = fd;
111 return stat;
112 }
113
114 bool File::isOpen() {
115 return this->m_fd > 0;
116 }
117
119 // make sure it has been opened
120 if (OPEN_NO_MODE == this->m_mode) {
121 return NOT_OPENED;
122 }
123
124 File::Status fileStatus = OP_OK;
125
126#ifdef __linux__
127 NATIVE_INT_TYPE stat = posix_fallocate(this->m_fd, offset, len);
128
129 if (stat) {
130 switch (stat) {
131 case ENOSPC:
132 case EFBIG:
133 fileStatus = NO_SPACE;
134 break;
135 case EBADF:
136 fileStatus = DOESNT_EXIST;
137 break;
138 default:
139 fileStatus = OTHER_ERROR;
140 break;
141 }
142 }
143#endif
144
145 return fileStatus;
146 }
147
148 File::Status File::seek(NATIVE_INT_TYPE offset, bool absolute) {
149
150 // make sure it has been opened
151 if (OPEN_NO_MODE == this->m_mode) {
152 return NOT_OPENED;
153 }
154
155 Status stat = OP_OK;
156 NATIVE_INT_TYPE whence = absolute?SEEK_SET:SEEK_CUR;
157
158 off_t act_off = ::lseek(this->m_fd,offset,whence);
159
160 // No error would be a normal one for this simple
161 // class, so return other error
162 if (act_off != offset) {
163 if (-1 == act_off) {
164 this->m_lastError = errno;
165 stat = OTHER_ERROR;
166 } else {
167 stat = BAD_SIZE;
168 }
169 }
170
171 return stat;
172 }
173
174 File::Status File::read(void * buffer, NATIVE_INT_TYPE &size, bool waitForFull) {
175
176 FW_ASSERT(buffer);
177
178 // make sure it has been opened
179 if (OPEN_NO_MODE == this->m_mode) {
180 size = 0;
181 return NOT_OPENED;
182 }
183 // Validate read size before entering reading loop. Linux's read call expects size_t, which
184 // is defined as an unsigned value. Thus 0 and negative values rejected.
185 if (size <= 0) {
186 size = 0;
187 return BAD_SIZE;
188 }
189
190 NATIVE_INT_TYPE accSize = 0; // accumulated size
191
192 Status stat = OP_OK;
193
194 NATIVE_INT_TYPE maxIters = size*2; // loop limit; couldn't block more times than number of bytes
195
196 while (maxIters > 0) {
197
198 ssize_t readSize = ::read(this->m_fd,
199#ifdef __VXWORKS__
200 static_cast<char*>(buffer)
201#else
202 buffer
203#endif
204 ,size-accSize);
205
206 if (readSize != size-accSize) {
207 // could be an error
208 if (-1 == readSize) {
209 switch (errno) {
210 case EINTR: // read was interrupted
211 maxIters--; // decrement loop count
212 continue;
213 default:
214 stat = OTHER_ERROR;
215 break;
216 }
217 this->m_lastError = errno;
218 accSize = 0;
219 break; // break out of while loop
220 } else if (0 == readSize) { // end of file
221 break;
222 } else { // partial read so adjust read point and size
223 accSize += readSize;
224 if (not waitForFull) {
225 break; // break out of while loop
226 } else {
227 // in order to move the pointer ahead, we need to cast it
228 U8* charPtr = static_cast<U8*>(buffer);
229 charPtr = &charPtr[readSize];
230 buffer = static_cast<void*>(charPtr);
231 }
232 maxIters--; // decrement loop count
233 }
234
235 } else { // got number we wanted
236 accSize += readSize;
237 break; // break out of while loop
238 }
239
240 maxIters--; // decrement loop count
241
242 } // end read while loop
243
244 // make sure we didn't exceed loop count
245 FW_ASSERT(maxIters > 0);
246
247 size = accSize;
248
249 return stat;
250 }
251
252 File::Status File::write(const void * buffer, NATIVE_INT_TYPE &size, bool waitForDone) {
253
254 // make sure it has been opened
255 if (OPEN_NO_MODE == this->m_mode) {
256 size = 0;
257 return NOT_OPENED;
258 }
259 // Validate read size before entering reading loop. Linux's read call expects size_t, which
260 // is defined as an unsigned value. Thus 0 and negative values rejected.
261 if (size <= 0) {
262 size = 0;
263 return BAD_SIZE;
264 }
265
266 Status stat = OP_OK;
267 // just check for EINTR
268 NATIVE_INT_TYPE maxIters = size*2; // loop limit; couldn't block more times than number of bytes
269 while (maxIters > 0) {
270 NATIVE_INT_TYPE writeSize = ::write(this->m_fd,
271#ifdef __VXWORKS__
272 static_cast<char*>(const_cast<void*>(buffer)) // Ugly, but that's how VxWorks likes to roll...
273#else
274 buffer
275#endif
276 ,size);
277
278 if (-1 == writeSize) {
279 switch (errno) {
280 case EINTR: // write was interrupted
281 maxIters--; // decrement loop count
282 continue;
283 case ENOSPC:
284 stat = NO_SPACE;
285 break;
286 default:
287 DEBUG_PRINT("Error %d during write of 0x%p, addrMod %d, size %d, sizeMod %d\n",
288 errno, buffer, static_cast<POINTER_CAST>(buffer) % 512, size, size % 512);
289 stat = OTHER_ERROR;
290 break;
291 }
292 this->m_lastError = errno;
293 break; // break out of while loop
294 } else {
295 size = writeSize;
296
297#ifdef __linux__
298 if ((OPEN_SYNC_DIRECT_WRITE != this->m_mode) && (waitForDone)) {
299 NATIVE_UINT_TYPE position = lseek(this->m_fd, 0, SEEK_CUR);
300 sync_file_range(this->m_fd, position - writeSize, writeSize,
301 SYNC_FILE_RANGE_WAIT_BEFORE
302 | SYNC_FILE_RANGE_WRITE
303 | SYNC_FILE_RANGE_WAIT_AFTER);
304 }
305#endif
306
307 break; // break out of while loop
308 }
309 }
310
311 return stat;
312 }
313
314 // NOTE(mereweth) - see http://lkml.iu.edu/hypermail/linux/kernel/1005.2/01845.html
315 // recommendation from Linus Torvalds, but doesn't seem to be that fast
316 File::Status File::bulkWrite(const void * buffer, NATIVE_UINT_TYPE &totalSize,
317 NATIVE_INT_TYPE chunkSize) {
318
319 // make sure it has been opened
320 if (OPEN_NO_MODE == this->m_mode) {
321 totalSize = 0;
322 return NOT_OPENED;
323 }
324 // Validate read size before entering reading loop. Linux's read call expects size_t, which
325 // is defined as an unsigned value. Thus 0 and negative values rejected.
326 if (totalSize == 0) {
327 totalSize = 0;
328 return BAD_SIZE;
329 }
330 else if (chunkSize <= 0) {
331 totalSize = 0;
332 return BAD_SIZE;
333 }
334
335#ifdef __linux__
336 const NATIVE_UINT_TYPE startPosition = lseek(this->m_fd, 0, SEEK_CUR);
337#endif
338 NATIVE_UINT_TYPE newBytesWritten = 0;
339
340 for (NATIVE_UINT_TYPE idx = 0; idx < totalSize; idx += chunkSize) {
341 NATIVE_INT_TYPE size = chunkSize;
342 // if we're on the last iteration and length isn't a multiple of chunkSize
343 if (idx + chunkSize > totalSize) {
344 size = totalSize - idx;
345 }
346 const NATIVE_INT_TYPE toWrite = size;
347 FW_ASSERT(idx + size <= totalSize, idx + size);
348 const Os::File::Status fileStatus = this->write(static_cast<const U8*>(buffer) + idx, size, false);
349 if (!(fileStatus == Os::File::OP_OK
350 && size == static_cast<NATIVE_INT_TYPE>(toWrite))) {
351 totalSize = newBytesWritten;
352 return fileStatus;
353 }
354
355#ifdef __linux__
356 sync_file_range(this->m_fd,
357 startPosition + newBytesWritten,
358 chunkSize,
359 SYNC_FILE_RANGE_WRITE);
360
361 if (newBytesWritten) {
362 sync_file_range(this->m_fd,
363 startPosition + newBytesWritten - chunkSize,
364 chunkSize,
365 SYNC_FILE_RANGE_WAIT_BEFORE
366 | SYNC_FILE_RANGE_WRITE
367 | SYNC_FILE_RANGE_WAIT_AFTER);
368
369 posix_fadvise(this->m_fd,
370 startPosition + newBytesWritten - chunkSize,
371 chunkSize, POSIX_FADV_DONTNEED);
372 }
373#endif
374
375 newBytesWritten += toWrite;
376 }
377
378 totalSize = newBytesWritten;
379 return OP_OK;
380 }
381
383 // make sure it has been opened
384 if (OPEN_NO_MODE == this->m_mode) {
385 return NOT_OPENED;
386 }
387
388 File::Status stat = OP_OK;
389
390 if (-1 == fsync(this->m_fd)) {
391 switch (errno) {
392 case ENOSPC:
393 stat = NO_SPACE;
394 break;
395 default:
396 stat = OTHER_ERROR;
397 break;
398 }
399 }
400
401 return stat;
402 }
403
404 void File::close() {
405 if ((this->m_fd != -1) and (this->m_mode != OPEN_NO_MODE)) {
406 (void)::close(this->m_fd);
407 this->m_fd = -1;
408 }
409 this->m_mode = OPEN_NO_MODE;
410 }
411
413 return this->m_lastError;
414 }
415
416 const char* File::getLastErrorString() {
417 return strerror(this->m_lastError);
418 }
419
421 {
422
423 // make sure it has been opened
424 if (OPEN_NO_MODE == this->m_mode) {
425 crc = 0;
426 return NOT_OPENED;
427 }
428
429 const U32 maxChunkSize = 32;
430 const U32 initialSeed = 0xFFFFFFFF;
431
432 // Seek to beginning of file
433 Status status = seek(0, true);
434 if (status != OP_OK) {
435 crc = 0;
436 return status;
437 }
438
439 U8 file_buffer[maxChunkSize];
440
441 bool endOfFile = false;
442
443 U32 seed = initialSeed;
444 const U32 maxIters = std::numeric_limits<U32>::max(); // loop limit
445 U32 numIters = 0;
446
447 while (!endOfFile && numIters < maxIters) {
448
449 ++numIters;
450 int chunkSize = maxChunkSize;
451
452 status = read(file_buffer, chunkSize, false);
453 if (status == OP_OK) {
454 // chunkSize modified by file.read
455
456 if (chunkSize == 0) {
457 endOfFile = true;
458 continue;
459 }
460
461 int chunkIdx = 0;
462
463 while (chunkIdx < chunkSize) {
464 seed = update_crc_32(seed, file_buffer[chunkIdx]);
465 chunkIdx++;
466 }
467
468 } else {
469 crc = 0;
470 return status;
471 }
472 }
473
474 if (!endOfFile) {
475 crc = 0;
476 return OTHER_ERROR;
477 }
478 else {
479 crc = seed;
480 return OP_OK;
481 }
482 }
483}
#define FW_ASSERT(...)
Definition Assert.hpp:7
PlatformPointerCastType POINTER_CAST
Definition BasicTypes.h:53
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.
#define DEBUG_PRINT(x,...)
File()
Constructor.
Definition File.cpp:8
bool isOpen()
check if file descriptor is open or not.
Definition File.cpp:20
void close()
close file
Definition File.cpp:36
@ DOESNT_EXIST
File doesn't exist (for read)
Definition File.hpp:25
@ NOT_OPENED
file hasn't been opened yet
Definition File.hpp:29
@ BAD_SIZE
Invalid size parameter.
Definition File.hpp:28
@ OTHER_ERROR
A catch-all for other errors. Have to look in implementation-specific code.
Definition File.hpp:31
@ FILE_EXISTS
file already exist (for CREATE with O_EXCL enabled)
Definition File.hpp:30
@ NO_PERMISSION
No permission to read/write file.
Definition File.hpp:27
@ OP_OK
Operation was successful.
Definition File.hpp:24
@ NO_SPACE
No space left.
Definition File.hpp:26
Status write(const void *buffer, NATIVE_INT_TYPE &size, bool waitForDone=true)
write size; will return amount written or errno
Definition File.cpp:32
const char * getLastErrorString()
get a string of the last error (typically from strerror)
Definition File.cpp:42
Status seek(NATIVE_INT_TYPE offset, bool absolute=true)
seek to location. If absolute = true, absolute from beginning of file
Definition File.cpp:24
Status prealloc(NATIVE_INT_TYPE offset, NATIVE_INT_TYPE len)
Definition File.cpp:118
Status flush()
flush data to disk. No-op on systems that do not support.
Definition File.cpp:382
@ OPEN_SYNC_DIRECT_WRITE
Open file for writing, bypassing all caching. Requires data alignment.
Definition File.hpp:18
@ OPEN_APPEND
Open file for appending.
Definition File.hpp:20
@ OPEN_WRITE
Open file for writing.
Definition File.hpp:16
@ OPEN_NO_MODE
File mode not yet selected.
Definition File.hpp:14
@ OPEN_SYNC_WRITE
Open file for writing; writes don't return until data is on disk.
Definition File.hpp:17
@ OPEN_CREATE
Open file for writing and truncates file if it exists, ie same flags as creat()
Definition File.hpp:19
@ OPEN_READ
Open file for reading.
Definition File.hpp:15
NATIVE_INT_TYPE getLastError()
read back last error code (typically errno)
Definition File.cpp:38
Status open(const char *fileName, Mode mode)
open file. Writing creates file if it doesn't exist
Definition File.cpp:12
virtual ~File()
Destructor. Will close file if still open.
Definition File.cpp:10
Status bulkWrite(const void *buffer, NATIVE_UINT_TYPE &totalSize, NATIVE_INT_TYPE chunkSize)
write size; will return amount written or errno
Definition File.cpp:316
Status read(void *buffer, NATIVE_INT_TYPE &size, bool waitForFull=true)
waitForFull = true to wait for all bytes to be read
Definition File.cpp:28
Status calculateCRC32(U32 &crc)
calculates the CRC32 of the file
Definition File.cpp:420
unsigned long update_crc_32(unsigned long crc, char c)
Definition lib_crc.c:269
Definition File.cpp:6