F´ Flight Software - C/C++ Documentation
A framework for building embedded system applications to NASA flight quality standards.
Loading...
Searching...
No Matches
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
15namespace Os {
16namespace Posix {
17namespace 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
32static_assert(sizeof(FwSignedSizeType) >= sizeof(off_t),
33 "FwSizeType is not large enough to store values of type off_t");
34static_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
38static_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.");
40static_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.");
42static_assert(std::numeric_limits<FwSignedSizeType>::min() <= std::numeric_limits<off_t>::min(),
43 "Minimum value of FwSizeType larger than the minimum value of off_t. Configure a larger type.");
44static_assert(std::numeric_limits<FwSignedSizeType>::min() <= std::numeric_limits<ssize_t>::min(),
45 "Minimum value of FwSizeType larger than the minimum value of ssize_t. Configure a larger type.");
46
49 // Must properly duplicate the file handle
50 this->m_handle.m_file_descriptor = fcntl(other.m_handle.m_file_descriptor, F_DUPFD, 0);
51}
52
54 if (this != &other) {
55 this->m_handle.m_file_descriptor = fcntl(other.m_handle.m_file_descriptor, F_DUPFD, 0);
56 }
57 return *this;
58}
59
61 PosixFile::Mode requested_mode,
62 PosixFile::OverwriteType overwrite) {
63 PlatformIntType mode_flags = 0;
64 Status status = OP_OK;
65 switch (requested_mode) {
66 case OPEN_READ:
67 mode_flags = O_RDONLY;
68 break;
69 case OPEN_WRITE:
70 mode_flags = O_WRONLY | O_CREAT;
71 break;
72 case OPEN_SYNC_WRITE:
73 mode_flags = O_WRONLY | O_CREAT | O_SYNC;
74 break;
75 case OPEN_CREATE:
76 mode_flags =
77 O_WRONLY | O_CREAT | O_TRUNC | ((overwrite == PosixFile::OverwriteType::OVERWRITE) ? 0 : O_EXCL);
78 break;
79 case OPEN_APPEND:
80 mode_flags = O_WRONLY | O_CREAT | O_APPEND;
81 break;
82 default:
83 FW_ASSERT(0, requested_mode);
84 break;
85 }
86 PlatformIntType descriptor = ::open(filepath, mode_flags, USER_FLAGS);
88 PlatformIntType errno_store = errno;
89 status = Os::Posix::errno_to_file_status(errno_store);
90 }
91 this->m_handle.m_file_descriptor = descriptor;
92 return status;
93}
94
96 // Only close file handles that are not open
98 (void)::close(this->m_handle.m_file_descriptor);
100 }
101}
102
104 FwSignedSizeType current_position = 0;
105 Status status = this->position(current_position);
106 size_result = 0;
107 if (Os::File::Status::OP_OK == status) {
108 // Seek to the end of the file to determine size
109 off_t end_of_file = ::lseek(this->m_handle.m_file_descriptor, 0, SEEK_END);
110 if (PosixFileHandle::ERROR_RETURN_VALUE == end_of_file) {
111 PlatformIntType errno_store = errno;
112 status = Os::Posix::errno_to_file_status(errno_store);
113 } else {
114 // Return the file pointer back to the original position
115 off_t original = ::lseek(this->m_handle.m_file_descriptor, current_position, SEEK_SET);
116 if ((PosixFileHandle::ERROR_RETURN_VALUE == original) || (current_position != original)) {
117 PlatformIntType errno_store = errno;
118 status = Os::Posix::errno_to_file_status(errno_store);
119 }
120 }
121 size_result = end_of_file;
122 }
123 return status;
124}
125
127 Status status = OP_OK;
128 position_result = 0;
129 off_t actual = ::lseek(this->m_handle.m_file_descriptor, 0, SEEK_CUR);
131 PlatformIntType errno_store = errno;
132 status = Os::Posix::errno_to_file_status(errno_store);
133 }
134 position_result = static_cast<FwSignedSizeType>(actual);
135 return status;
136}
137
140 // posix_fallocate is only available with the posix C-API post version 200112L, however; it is not guaranteed that
141 // this call is properly implemented. This code starts with a status of "NOT_SUPPORTED". When the standard is met
142 // an attempt will be made to called posix_fallocate, and should that still return NOT_SUPPORTED then fallback
143 // code is engaged to synthesize this behavior.
144#if _POSIX_C_SOURCE >= 200112L
145 PlatformIntType errno_status = ::posix_fallocate(this->m_handle.m_file_descriptor, offset, length);
146 status = Os::Posix::errno_to_file_status(errno_status);
147#endif
148 // When the operation is not supported or posix-API is not sufficient, fallback to a slower algorithm
149 if (Os::File::Status::NOT_SUPPORTED == status) {
150 // Calculate size
151 FwSignedSizeType file_size = 0;
152 status = this->size(file_size);
153 if (Os::File::Status::OP_OK == status) {
154 // Calculate current position
155 FwSignedSizeType file_position = 0;
156 status = this->position(file_position);
157 if (Os::File::Status::OP_OK == status) {
158 // Check for integer overflow
159 if ((std::numeric_limits<FwSignedSizeType>::max() - offset - length) < 0) {
160 status = PosixFile::NO_SPACE;
161 } else if (file_size < (offset + length)) {
162 const FwSignedSizeType write_length = (offset + length) - file_size;
163 status = this->seek(file_size, PosixFile::SeekType::ABSOLUTE);
164 if (Os::File::Status::OP_OK == status) {
165 // Fill in zeros past size of file to ensure compatibility with fallocate
166 for (FwSignedSizeType i = 0; i < write_length; i++) {
167 FwSignedSizeType write_size = 1;
168 status = this->write(reinterpret_cast<const U8*>("\0"), write_size,
170 if (Status::OP_OK != status || write_size != 1) {
171 break;
172 }
173 }
174 // Return to original position
175 if (Os::File::Status::OP_OK == status) {
176 status = this->seek(file_position, PosixFile::SeekType::ABSOLUTE);
177 }
178 }
179 }
180 }
181 }
182 }
183 return status;
184}
185
187 Status status = OP_OK;
188 off_t actual =
189 ::lseek(this->m_handle.m_file_descriptor, offset, (seekType == SeekType::ABSOLUTE) ? SEEK_SET : SEEK_CUR);
190 PlatformIntType errno_store = errno;
192 status = Os::Posix::errno_to_file_status(errno_store);
193 } else if ((seekType == SeekType::ABSOLUTE) && (actual != offset)) {
195 }
196 return status;
197}
198
200 PosixFile::Status status = OP_OK;
201 if (PosixFileHandle::ERROR_RETURN_VALUE == ::fsync(this->m_handle.m_file_descriptor)) {
202 PlatformIntType errno_store = errno;
203 status = Os::Posix::errno_to_file_status(errno_store);
204 }
205 return status;
206}
207
209 Status status = OP_OK;
210 FwSignedSizeType accumulated = 0;
211 // Loop up to 2 times for each by, bounded to prevent overflow
212 const FwSignedSizeType maximum = (size > (std::numeric_limits<FwSignedSizeType>::max() / 2))
213 ? std::numeric_limits<FwSignedSizeType>::max()
214 : size * 2;
215
216 for (FwSignedSizeType i = 0; i < maximum && accumulated < size; i++) {
217 // char* for some posix implementations
218 ssize_t read_size = ::read(this->m_handle.m_file_descriptor, reinterpret_cast<CHAR*>(&buffer[accumulated]),
219 static_cast<size_t>(size - accumulated));
220 // Non-interrupt error
221 if (PosixFileHandle::ERROR_RETURN_VALUE == read_size) {
222 PlatformIntType errno_store = errno;
223 // Interrupted w/o read, try again
224 if (EINTR != errno_store) {
225 continue;
226 }
227 status = Os::Posix::errno_to_file_status(errno_store);
228 break;
229 }
230 // End-of-file
231 else if (read_size == 0) {
232 break;
233 }
234 accumulated += read_size;
235 // Stop looping when we had a good read and are not waiting
236 if (not wait) {
237 break;
238 }
239 }
240 size = accumulated;
241 return status;
242}
243
245 Status status = OP_OK;
246 FwSignedSizeType accumulated = 0;
247 // Loop up to 2 times for each by, bounded to prevent overflow
248 const FwSignedSizeType maximum = (size > (std::numeric_limits<FwSignedSizeType>::max() / 2))
249 ? std::numeric_limits<FwSignedSizeType>::max()
250 : size * 2;
251
252 for (FwSignedSizeType i = 0; i < maximum && accumulated < size; i++) {
253 // char* for some posix implementations
254 ssize_t write_size =
255 ::write(this->m_handle.m_file_descriptor, reinterpret_cast<const CHAR*>(&buffer[accumulated]),
256 static_cast<size_t>(size - accumulated));
257 // Non-interrupt error
258 if (PosixFileHandle::ERROR_RETURN_VALUE == write_size) {
259 PlatformIntType errno_store = errno;
260 // Interrupted w/o read, try again
261 if (EINTR != errno_store) {
262 continue;
263 }
264 status = Os::Posix::errno_to_file_status(errno_store);
265 break;
266 }
267 accumulated += write_size;
268 }
269 size = accumulated;
270 // When waiting, sync to disk
271 if (wait) {
272 PlatformIntType fsync_return = ::fsync(this->m_handle.m_file_descriptor);
273 if (PosixFileHandle::ERROR_RETURN_VALUE == fsync_return) {
274 PlatformIntType errno_store = errno;
275 status = Os::Posix::errno_to_file_status(errno_store);
276 }
277 }
278 return status;
279}
280
282 return &this->m_handle;
283}
284
285} // namespace File
286} // namespace Posix
287} // 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
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_WAIT
Do not wait for read/write operation to finish.
Definition File.hpp:57
@ OVERWRITE
Overwrite file when it exists and creation was requested.
Definition File.hpp:46
@ NO_SPACE
No space left.
Definition File.hpp:32
@ NOT_SUPPORTED
Kernel or file system does not support operation.
Definition File.hpp:37
@ OTHER_ERROR
A catch-all for other errors. Have to look in implementation-specific code.
Definition File.hpp:40
@ OP_OK
Operation was successful.
Definition File.hpp:30
@ ABSOLUTE
Absolute seek from beginning of file.
Definition File.hpp:52
@ 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:126
void close() override
close the file, if not opened then do nothing
Definition File.cpp:95
Status seek(FwSignedSizeType offset, SeekType seekType) override
seek the file pointer to the given offset
Definition File.cpp:186
Status preallocate(FwSignedSizeType offset, FwSignedSizeType length) override
pre-allocate file storage
Definition File.cpp:138
Status read(U8 *buffer, FwSignedSizeType &size, WaitType wait) override
read data from this file into supplied buffer bounded by size
Definition File.cpp:208
Status write(const U8 *buffer, FwSignedSizeType &size, WaitType wait) override
read data from this file into supplied buffer bounded by size
Definition File.cpp:244
FileHandle * getHandle() override
returns the raw file handle
Definition File.cpp:281
PosixFile()=default
constructor
Status size(FwSignedSizeType &size_result) override
get size of currently open file
Definition File.cpp:103
Status flush() override
flush file contents to storage
Definition File.cpp:199
PosixFile & operator=(const PosixFile &other)
assignment operator that copies the internal representation
Definition File.cpp:53
Os::FileInterface::Status open(const char *path, Mode mode, OverwriteType overwrite) override
open file with supplied path and mode
Definition File.cpp:60
File::Status errno_to_file_status(PlatformIntType errno_input)
Definition error.cpp:11
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