F´ Flight Software - C/C++ Documentation  devel
A framework for building embedded system applications to NASA flight quality standards.
File.cpp
Go to the documentation of this file.
1 // ======================================================================
2 // \title Os/Posix/File.cpp
3 // \brief posix implementation for Os::File
4 // ======================================================================
5 #include <fcntl.h>
6 #include <unistd.h>
7 #include <cerrno>
8 #include <limits>
9 
10 #include <Fw/Types/Assert.hpp>
11 #include <Os/File.hpp>
12 #include <Os/Posix/File.hpp>
13 #include <Os/Posix/error.hpp>
14 
15 namespace Os {
16 namespace Posix {
17 namespace File {
18 
19 // Sets up the default file permission as user read + user write
20 // Some posix systems (e.g. Darwin) use the older S_IREAD and S_IWRITE flags while other systems (e.g. Linux) use the
21 // newer S_IRUSR and S_IWUSR flags, and some don't support these flags at all. Hence, we look if flags are defined then
22 // set USER_FLAGS to be the set of flags supported or 0 in the case neither is defined.
23 #if defined(S_IREAD) && defined(S_IWRITE)
24 #define USER_FLAGS (S_IREAD | S_IWRITE)
25 #elif defined(S_IRUSR) && defined(S_IWUSR)
26 #define USER_FLAGS (S_IRUSR | S_IWUSR)
27 #else
28 #define USER_FLAGS (0)
29 #endif
30 
31 // Ensure size of FwSizeType is large enough to fit eh necessary range
32 static_assert(sizeof(FwSignedSizeType) >= sizeof(off_t),
33  "FwSizeType is not large enough to store values of type off_t");
34 static_assert(sizeof(FwSignedSizeType) >= sizeof(ssize_t),
35  "FwSizeType is not large enough to store values of type ssize_t");
36 
37 // Now check ranges of FwSizeType
38 static_assert(std::numeric_limits<FwSignedSizeType>::max() >= std::numeric_limits<off_t>::max(),
39  "Maximum value of FwSizeType less than the maximum value of off_t. Configure a larger type.");
40 static_assert(std::numeric_limits<FwSignedSizeType>::max() >= std::numeric_limits<ssize_t>::max(),
41  "Maximum value of FwSizeType less than the maximum value of ssize_t. Configure a larger type.");
43  "Minimum value of FwSizeType larger than the minimum value of off_t. Configure a larger type.");
45  "Minimum value of FwSizeType larger than the minimum value of ssize_t. Configure a larger type.");
46 
48 #ifndef TGT_OS_TYPE_VXWORKS
50  // Must properly duplicate the file handle
51  this->m_handle.m_file_descriptor = ::dup(other.m_handle.m_file_descriptor);
52 }
53 #endif
54 
55 #ifndef TGT_OS_TYPE_VXWORKS
57  if (this != &other) {
58  this->m_handle.m_file_descriptor = ::dup(other.m_handle.m_file_descriptor);
59  }
60  return *this;
61 }
62 #endif
63 
64 PosixFile::Status PosixFile::open(const char* filepath,
65  PosixFile::Mode requested_mode,
66  PosixFile::OverwriteType overwrite) {
67  PlatformIntType mode_flags = 0;
68  Status status = OP_OK;
69  switch (requested_mode) {
70  case OPEN_READ:
71  mode_flags = O_RDONLY;
72  break;
73  case OPEN_WRITE:
74  mode_flags = O_WRONLY | O_CREAT;
75  break;
76  case OPEN_SYNC_WRITE:
77  mode_flags = O_WRONLY | O_CREAT | O_SYNC;
78  break;
79  case OPEN_CREATE:
80  mode_flags =
81  O_WRONLY | O_CREAT | O_TRUNC | ((overwrite == PosixFile::OverwriteType::OVERWRITE) ? 0 : O_EXCL);
82  break;
83  case OPEN_APPEND:
84  mode_flags = O_WRONLY | O_CREAT | O_APPEND;
85  break;
86  default:
87  FW_ASSERT(0, requested_mode);
88  break;
89  }
90  PlatformIntType descriptor = ::open(filepath, mode_flags, USER_FLAGS);
91  if (PosixFileHandle::INVALID_FILE_DESCRIPTOR == descriptor) {
92  PlatformIntType errno_store = errno;
93  status = Os::Posix::errno_to_file_status(errno_store);
94  }
95  this->m_handle.m_file_descriptor = descriptor;
96  return status;
97 }
98 
100  // Only close file handles that are not open
102  (void)::close(this->m_handle.m_file_descriptor);
104  }
105 }
106 
108  FwSignedSizeType current_position = 0;
109  Status status = this->position(current_position);
110  size_result = 0;
111  if (Os::File::Status::OP_OK == status) {
112  // Seek to the end of the file to determine size
113  off_t end_of_file = ::lseek(this->m_handle.m_file_descriptor, 0, SEEK_END);
114  if (PosixFileHandle::ERROR_RETURN_VALUE == end_of_file) {
115  PlatformIntType errno_store = errno;
116  status = Os::Posix::errno_to_file_status(errno_store);
117  } else {
118  // Return the file pointer back to the original position
119  off_t original = ::lseek(this->m_handle.m_file_descriptor, current_position, SEEK_SET);
120  if ((PosixFileHandle::ERROR_RETURN_VALUE == original) || (current_position != original)) {
121  PlatformIntType errno_store = errno;
122  status = Os::Posix::errno_to_file_status(errno_store);
123  }
124  }
125  size_result = end_of_file;
126  }
127  return status;
128 }
129 
131  Status status = OP_OK;
132  position_result = 0;
133  off_t actual = ::lseek(this->m_handle.m_file_descriptor, 0, SEEK_CUR);
134  if (PosixFileHandle::ERROR_RETURN_VALUE == actual) {
135  PlatformIntType errno_store = errno;
136  status = Os::Posix::errno_to_file_status(errno_store);
137  }
138  position_result = static_cast<FwSignedSizeType>(actual);
139  return status;
140 }
141 
143  PosixFile::Status status = Os::File::Status::NOT_SUPPORTED;
144  // posix_fallocate is only available with the posix C-API post version 200112L, however; it is not guaranteed that
145  // this call is properly implemented. This code starts with a status of "NOT_SUPPORTED". When the standard is met
146  // an attempt will be made to called posix_fallocate, and should that still return NOT_SUPPORTED then fallback
147  // code is engaged to synthesize this behavior.
148 #if _POSIX_C_SOURCE >= 200112L
149  PlatformIntType errno_status = ::posix_fallocate(this->m_handle.m_file_descriptor, offset, length);
150  status = Os::Posix::errno_to_file_status(errno_status);
151 #endif
152  // When the operation is not supported or posix-API is not sufficient, fallback to a slower algorithm
153  if (Os::File::Status::NOT_SUPPORTED == status) {
154  // Calculate size
155  FwSignedSizeType file_size = 0;
156  status = this->size(file_size);
157  if (Os::File::Status::OP_OK == status) {
158  // Calculate current position
159  FwSignedSizeType file_position = 0;
160  status = this->position(file_position);
161  if (Os::File::Status::OP_OK == status) {
162  // Check for integer overflow
163  if ((std::numeric_limits<FwSignedSizeType>::max() - offset - length) < 0) {
164  status = PosixFile::NO_SPACE;
165  } else if (file_size < (offset + length)) {
166  const FwSignedSizeType write_length = (offset + length) - file_size;
167  status = this->seek(file_size, PosixFile::SeekType::ABSOLUTE);
168  if (Os::File::Status::OP_OK == status) {
169  // Fill in zeros past size of file to ensure compatibility with fallocate
170  for (FwSignedSizeType i = 0; i < write_length; i++) {
171  FwSignedSizeType write_size = 1;
172  status = this->write(reinterpret_cast<const U8*>("\0"), write_size,
173  PosixFile::WaitType::NO_WAIT);
174  if (Status::OP_OK != status || write_size != 1) {
175  break;
176  }
177  }
178  // Return to original position
179  if (Os::File::Status::OP_OK == status) {
180  status = this->seek(file_position, PosixFile::SeekType::ABSOLUTE);
181  }
182  }
183  }
184  }
185  }
186  }
187  return status;
188 }
189 
191  Status status = OP_OK;
192  off_t actual =
193  ::lseek(this->m_handle.m_file_descriptor, offset, (seekType == SeekType::ABSOLUTE) ? SEEK_SET : SEEK_CUR);
194  PlatformIntType errno_store = errno;
195  if (actual == PosixFileHandle::ERROR_RETURN_VALUE) {
196  status = Os::Posix::errno_to_file_status(errno_store);
197  } else if ((seekType == SeekType::ABSOLUTE) && (actual != offset)) {
199  }
200  return status;
201 }
202 
204  PosixFile::Status status = OP_OK;
205  if (PosixFileHandle::ERROR_RETURN_VALUE == ::fsync(this->m_handle.m_file_descriptor)) {
206  PlatformIntType errno_store = errno;
207  status = Os::Posix::errno_to_file_status(errno_store);
208  }
209  return status;
210 }
211 
213  Status status = OP_OK;
214  FwSignedSizeType accumulated = 0;
215  // Loop up to 2 times for each by, bounded to prevent overflow
216  const FwSignedSizeType maximum = (size > (std::numeric_limits<FwSignedSizeType>::max() / 2))
217  ? std::numeric_limits<FwSignedSizeType>::max()
218  : size * 2;
219 
220  for (FwSignedSizeType i = 0; i < maximum && accumulated < size; i++) {
221  // char* for some posix implementations
222  ssize_t read_size = ::read(this->m_handle.m_file_descriptor, reinterpret_cast<CHAR*>(&buffer[accumulated]),
223  static_cast<size_t>(size - accumulated));
224  // Non-interrupt error
225  if (PosixFileHandle::ERROR_RETURN_VALUE == read_size) {
226  PlatformIntType errno_store = errno;
227  // Interrupted w/o read, try again
228  if (EINTR != errno_store) {
229  continue;
230  }
231  status = Os::Posix::errno_to_file_status(errno_store);
232  break;
233  }
234  // End-of-file
235  else if (read_size == 0) {
236  break;
237  }
238  accumulated += read_size;
239  // Stop looping when we had a good read and are not waiting
240  if (not wait) {
241  break;
242  }
243  }
244  size = accumulated;
245  return status;
246 }
247 
249  Status status = OP_OK;
250  FwSignedSizeType accumulated = 0;
251  // Loop up to 2 times for each by, bounded to prevent overflow
252  const FwSignedSizeType maximum = (size > (std::numeric_limits<FwSignedSizeType>::max() / 2))
253  ? std::numeric_limits<FwSignedSizeType>::max()
254  : size * 2;
255 
256  for (FwSignedSizeType i = 0; i < maximum && accumulated < size; i++) {
257  // char* for some posix implementations
258  ssize_t write_size =
259  ::write(this->m_handle.m_file_descriptor, reinterpret_cast<const CHAR*>(&buffer[accumulated]),
260  static_cast<size_t>(size - accumulated));
261  // Non-interrupt error
262  if (PosixFileHandle::ERROR_RETURN_VALUE == write_size) {
263  PlatformIntType errno_store = errno;
264  // Interrupted w/o read, try again
265  if (EINTR != errno_store) {
266  continue;
267  }
268  status = Os::Posix::errno_to_file_status(errno_store);
269  break;
270  }
271  accumulated += write_size;
272  }
273  size = accumulated;
274  // When waiting, sync to disk
275  if (wait) {
276  PlatformIntType fsync_return = ::fsync(this->m_handle.m_file_descriptor);
277  if (PosixFileHandle::ERROR_RETURN_VALUE == fsync_return) {
278  PlatformIntType errno_store = errno;
279  status = Os::Posix::errno_to_file_status(errno_store);
280  }
281  }
282  return status;
283 }
284 
286  return &this->m_handle;
287 }
288 
289 } // namespace File
290 } // namespace Posix
291 } // namespace Os
#define FW_ASSERT(...)
Definition: Assert.hpp:14
uint8_t U8
8-bit unsigned integer
Definition: BasicTypes.h:30
char CHAR
Definition: BasicTypes.h:32
static U32 min(const U32 a, const U32 b)
Definition: Checksum.cpp:16
int PlatformIntType
DefaultTypes.hpp provides fallback defaults for the platform types.
PlatformSignedSizeType FwSignedSizeType
Definition: FpConfig.h:30
#define USER_FLAGS
Definition: File.cpp:28
@ NO_SPACE
No space left.
Definition: File.hpp:32
@ OP_OK
Operation was successful.
Definition: File.hpp:30
@ OPEN_WRITE
Open file for writing.
Definition: File.hpp:23
@ OPEN_CREATE
Open file for writing and truncates file if it exists, ie same flags as creat()
Definition: File.hpp:22
@ OPEN_READ
Open file for reading.
Definition: File.hpp:21
@ OPEN_APPEND
Open file for appending.
Definition: File.hpp:25
@ OPEN_SYNC_WRITE
Open file for writing; writes don't return until data is on disk.
Definition: File.hpp:24
posix implementation of Os::File
Definition: File.hpp:29
Status position(FwSignedSizeType &position_result) override
get file pointer position of the currently open file
Definition: File.cpp:130
void close() override
close the file, if not opened then do nothing
Definition: File.cpp:99
Status seek(FwSignedSizeType offset, SeekType seekType) override
seek the file pointer to the given offset
Definition: File.cpp:190
Status preallocate(FwSignedSizeType offset, FwSignedSizeType length) override
pre-allocate file storage
Definition: File.cpp:142
Status read(U8 *buffer, FwSignedSizeType &size, WaitType wait) override
read data from this file into supplied buffer bounded by size
Definition: File.cpp:212
Status write(const U8 *buffer, FwSignedSizeType &size, WaitType wait) override
read data from this file into supplied buffer bounded by size
Definition: File.cpp:248
FileHandle * getHandle() override
returns the raw file handle
Definition: File.cpp:285
PosixFile()=default
constructor
Status size(FwSignedSizeType &size_result) override
get size of currently open file
Definition: File.cpp:107
Status flush() override
flush file contents to storage
Definition: File.cpp:203
PosixFile & operator=(const PosixFile &other)
assignment operator that copies the internal representation
Definition: File.cpp:56
Os::FileInterface::Status open(const char *path, Mode mode, OverwriteType overwrite) override
open file with supplied path and mode
Definition: File.cpp:64
@ OP_OK
Operation succeeded.
Definition: Os.hpp:26
File::Status errno_to_file_status(PlatformIntType errno_input)
Definition: error.cpp:11
@ OTHER_ERROR
A catch-all for other errors. Have to look in implementation-specific code.
base implementation of FileHandle
Definition: File.hpp:14
PlatformIntType m_file_descriptor
Posix file descriptor.
Definition: File.hpp:20
static constexpr PlatformIntType INVALID_FILE_DESCRIPTOR
Definition: File.hpp:16
static constexpr PlatformIntType ERROR_RETURN_VALUE
Definition: File.hpp:17