F´ Flight Software - C/C++ Documentation  NASA-v2.0.1
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>
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