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