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