F´ Flight Software - C/C++ Documentation  devel
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>
2 #include <Os/File.hpp>
3 #include <Fw/Types/Assert.hpp>
4 #include <Os/Stubs/FileStubs.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 
15 namespace Os {
16 
17  static ReadInterceptor readInterceptor = nullptr;
18  static void *readInterceptorPtr = nullptr;
19 
21  static void *writeInterceptorPtr = nullptr;
22 
23  static OpenInterceptor openInterceptor = nullptr;
24  static void *openInterceptorPtr = nullptr;
25 
26  static SeekInterceptor seekInterceptor = nullptr;
27  static void *seekInterceptorPtr = nullptr;
28 
30 
31  void registerReadInterceptor(ReadInterceptor funcPtr, void *ptr) {
32  readInterceptor = funcPtr;
33  readInterceptorPtr = ptr;
34  }
35 
37  readInterceptor = nullptr;
38  }
39 
40  void registerWriteInterceptor(WriteInterceptor funcPtr, void *ptr) {
41  writeInterceptor = funcPtr;
42  writeInterceptorPtr = ptr;
43  }
44 
46  writeInterceptor = nullptr;
47  }
48 
49  void registerOpenInterceptor(OpenInterceptor funcPtr, void *ptr) {
50  openInterceptor = funcPtr;
51  openInterceptorPtr = ptr;
52  }
53 
55  openInterceptor = nullptr;
56  }
57 
58  void registerSeekInterceptor(SeekInterceptor funcPtr, void *ptr) {
59  seekInterceptor = funcPtr;
60  seekInterceptorPtr = ptr;
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:14
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
Status
Definition: File.hpp:23
@ OP_OK
Operation was successful.
Definition: File.hpp:24
@ OP_OK
Operation was successful.
Definition: FileSystem.hpp:15
@ NO_PERMISSION
No permission to write.
Definition: FileSystem.hpp:18
@ OTHER_ERROR
other OS-specific error
Definition: FileSystem.hpp:25
@ NO_SPACE
No space left.
Definition: FileSystem.hpp:17
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