F´ Flight Software - C/C++ Documentation
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/File.cpp
3 // \brief common function implementation for Os::File
4 // ======================================================================
5 #include <Fw/Types/Assert.hpp>
7 #include <Os/File.hpp>
8 #include <algorithm>
10 
11 extern "C" {
12 #include <Utils/Hash/libcrc/lib_crc.h> // borrow CRC
13 }
14 namespace Os {
15 
16 File::File() : m_crc_buffer(), m_handle_storage(), m_delegate(*FileInterface::getDelegate(m_handle_storage)) {
17  FW_ASSERT(&this->m_delegate == reinterpret_cast<FileInterface*>(&this->m_handle_storage[0]));
18 }
19 
21  FW_ASSERT(&this->m_delegate == reinterpret_cast<FileInterface*>(&this->m_handle_storage[0]));
22  if (this->m_mode != OPEN_NO_MODE) {
23  this->close();
24  }
25  m_delegate.~FileInterface();
26 }
27 
28 File::File(const File& other)
29  : m_mode(other.m_mode),
30  m_crc(other.m_crc),
31  m_crc_buffer(),
32  m_handle_storage(),
33  m_delegate(*FileInterface::getDelegate(m_handle_storage, &other.m_delegate)) {
34  FW_ASSERT(&this->m_delegate == reinterpret_cast<FileInterface*>(&this->m_handle_storage[0]));
35 }
36 
37 File& File::operator=(const File& other) {
38  if (this != &other) {
39  this->m_mode = other.m_mode;
40  this->m_crc = other.m_crc;
41  this->m_delegate = *FileInterface::getDelegate(m_handle_storage, &other.m_delegate);
42  }
43  return *this;
44 }
45 
46 File::Status File::open(const CHAR* filepath, File::Mode requested_mode) {
47  return this->open(filepath, requested_mode, OverwriteType::NO_OVERWRITE);
48 }
49 
50 File::Status File::open(const CHAR* filepath, File::Mode requested_mode, File::OverwriteType overwrite) {
51  FW_ASSERT(nullptr != filepath);
52  return this->open(filepath, static_cast<FwSizeType>(FileNameStringSize + 1), requested_mode, overwrite);
53 }
54 
55 File::Status File::open(const CHAR* filepath, FwSizeType length, File::Mode requested_mode) {
56  return this->open(filepath, length, requested_mode, OverwriteType::NO_OVERWRITE);
57 }
58 
59 File::Status File::open(const CHAR* filepath,
60  FwSizeType length,
61  File::Mode requested_mode,
62  File::OverwriteType overwrite) {
63  FW_ASSERT(&this->m_delegate == reinterpret_cast<FileInterface*>(&this->m_handle_storage[0]));
64  FW_ASSERT(nullptr != filepath);
65  const FwSizeType string_len = static_cast<FwSizeType>(Fw::StringUtils::string_length(filepath, length));
66  FW_ASSERT(string_len < length, static_cast<FwAssertArgType>(string_len), static_cast<FwAssertArgType>(length));
67  FW_ASSERT(File::Mode::OPEN_NO_MODE < requested_mode && File::Mode::MAX_OPEN_MODE > requested_mode);
68  FW_ASSERT((0 <= this->m_mode) && (this->m_mode < Mode::MAX_OPEN_MODE));
69  FW_ASSERT((0 <= overwrite) && (overwrite < OverwriteType::MAX_OVERWRITE_TYPE));
70  // Check for already opened file
71  if (this->isOpen()) {
72  return File::Status::INVALID_MODE;
73  }
74  File::Status status = this->m_delegate.open(filepath, requested_mode, overwrite);
75  if (status == File::Status::OP_OK) {
76  this->m_mode = requested_mode;
77  // Reset any open CRC calculations
78  this->m_crc = File::INITIAL_CRC;
79  }
80 
81  return status;
82 }
83 
84 File::Status File::open(const Fw::ConstStringBase& path, File::Mode requested_mode) {
85  return this->open(path.toChar(), static_cast<FwSizeType>(path.getCapacity()), requested_mode,
86  OverwriteType::NO_OVERWRITE);
87 }
88 
89 File::Status File::open(const Fw::ConstStringBase& path, File::Mode requested_mode, File::OverwriteType overwrite) {
90  return this->open(path.toChar(), static_cast<FwSizeType>(path.getCapacity()), requested_mode, overwrite);
91 }
92 
93 void File::close() {
94  FW_ASSERT(&this->m_delegate == reinterpret_cast<FileInterface*>(&this->m_handle_storage[0]));
95  FW_ASSERT(this->m_mode < Mode::MAX_OPEN_MODE);
96  FW_ASSERT((0 <= this->m_mode) && (this->m_mode < Mode::MAX_OPEN_MODE));
97  this->m_delegate.close();
98  this->m_mode = Mode::OPEN_NO_MODE;
99 }
100 
101 bool File::isOpen() const {
102  FW_ASSERT(&this->m_delegate == reinterpret_cast<const FileInterface*>(&this->m_handle_storage[0]));
103  FW_ASSERT((0 <= this->m_mode) && (this->m_mode < Mode::MAX_OPEN_MODE));
104  return this->m_mode != Mode::OPEN_NO_MODE;
105 }
106 
108  FW_ASSERT(&this->m_delegate == reinterpret_cast<FileInterface*>(&this->m_handle_storage[0]));
109  FW_ASSERT((0 <= this->m_mode) && (this->m_mode < Mode::MAX_OPEN_MODE));
110  if (OPEN_NO_MODE == this->m_mode) {
111  return File::Status::NOT_OPENED;
112  }
113  return this->m_delegate.size(size_result);
114 }
115 
117  FW_ASSERT(&this->m_delegate == reinterpret_cast<FileInterface*>(&this->m_handle_storage[0]));
118  FW_ASSERT((0 <= this->m_mode) && (this->m_mode < Mode::MAX_OPEN_MODE));
119  // Check that the file is open before attempting operation
120  if (OPEN_NO_MODE == this->m_mode) {
121  return File::Status::NOT_OPENED;
122  }
123  return this->m_delegate.position(position_result);
124 }
125 
127  FW_ASSERT(&this->m_delegate == reinterpret_cast<FileInterface*>(&this->m_handle_storage[0]));
128  FW_ASSERT((0 <= this->m_mode) && (this->m_mode < Mode::MAX_OPEN_MODE));
129  // Check that the file is open before attempting operation
130  if (OPEN_NO_MODE == this->m_mode) {
131  return File::Status::NOT_OPENED;
132  } else if (OPEN_READ == this->m_mode) {
133  return File::Status::INVALID_MODE;
134  }
135  return this->m_delegate.preallocate(offset, length);
136 }
137 
139  FW_ASSERT(&this->m_delegate == reinterpret_cast<FileInterface*>(&this->m_handle_storage[0]));
140  FW_ASSERT((0 <= seekType) && (seekType < SeekType::MAX_SEEK_TYPE));
141  // Cannot do a seek with a negative offset in absolute mode
142  FW_ASSERT((seekType == File::SeekType::RELATIVE) || (offset >= 0));
143  FW_ASSERT((0 <= this->m_mode) && (this->m_mode < Mode::MAX_OPEN_MODE));
144  // Check that the file is open before attempting operation
145  if (OPEN_NO_MODE == this->m_mode) {
146  return File::Status::NOT_OPENED;
147  }
148  return this->m_delegate.seek(offset, seekType);
149 }
150 
153  // If the offset can be represented by a signed value, then we can perform a single seek
154  if (static_cast<FwSizeType>(std::numeric_limits<FwSignedSizeType>::max()) >= offset) {
155  // Check that the bounding above is correct
156  FW_ASSERT(static_cast<FwSignedSizeType>(offset) >= 0);
157  status = this->seek(static_cast<FwSignedSizeType>(offset), File::SeekType::ABSOLUTE);
158  }
159  // Otherwise, a full seek to any value represented by FwSizeType can be performed
160  // by at most 3 seeks of a FwSignedSizeType. Two half seeks (rounded down) that are
161  // strictly bounded by std::numeric_limits<FwSignedSizeType>::max() and one seek of
162  // a possibile "odd" byte to ensure odds offsets do not introduce an off-by-one-error.
163  // Thus we perform 3 seeks to guarantee that we can reach any position.
164  else {
165  FwSignedSizeType half_offset = static_cast<FwSignedSizeType>(offset >> 1);
166  bool is_odd = (offset % 2) == 1;
167  status = this->seek(half_offset, File::SeekType::ABSOLUTE);
168  if (status == File::Status::OP_OK) {
169  status = this->seek(half_offset, File::SeekType::RELATIVE);
170  }
171  if (status == File::Status::OP_OK) {
172  status = this->seek((is_odd) ? 1 : 0, File::SeekType::RELATIVE);
173  }
174  }
175  return status;
176 }
177 
179  FW_ASSERT(&this->m_delegate == reinterpret_cast<FileInterface*>(&this->m_handle_storage[0]));
180  FW_ASSERT(this->m_mode < Mode::MAX_OPEN_MODE);
181  // Check that the file is open before attempting operation
182  if (OPEN_NO_MODE == this->m_mode) {
183  return File::Status::NOT_OPENED;
184  } else if (OPEN_READ == this->m_mode) {
185  return File::Status::INVALID_MODE;
186  }
187  return this->m_delegate.flush();
188 }
189 
191  return this->read(buffer, size, WaitType::WAIT);
192 }
193 
195  FW_ASSERT(&this->m_delegate == reinterpret_cast<FileInterface*>(&this->m_handle_storage[0]));
196  FW_ASSERT(buffer != nullptr);
197  FW_ASSERT(this->m_mode < Mode::MAX_OPEN_MODE);
198  // Check that the file is open before attempting operation
199  if (OPEN_NO_MODE == this->m_mode) {
200  size = 0;
201  return File::Status::NOT_OPENED;
202  } else if (OPEN_READ != this->m_mode) {
203  size = 0;
204  return File::Status::INVALID_MODE;
205  }
206  return this->m_delegate.read(buffer, size, wait);
207 }
208 
209 File::Status File::write(const U8* buffer, FwSizeType& size) {
210  return this->write(buffer, size, WaitType::WAIT);
211 }
212 
213 File::Status File::write(const U8* buffer, FwSizeType& size, File::WaitType wait) {
214  FW_ASSERT(&this->m_delegate == reinterpret_cast<FileInterface*>(&this->m_handle_storage[0]));
215  FW_ASSERT(buffer != nullptr);
216  FW_ASSERT(this->m_mode < Mode::MAX_OPEN_MODE);
217  // Check that the file is open before attempting operation
218  if (OPEN_NO_MODE == this->m_mode) {
219  size = 0;
220  return File::Status::NOT_OPENED;
221  } else if (OPEN_READ == this->m_mode) {
222  size = 0;
223  return File::Status::INVALID_MODE;
224  }
225  return this->m_delegate.write(buffer, size, wait);
226 }
227 
229  FW_ASSERT(&this->m_delegate == reinterpret_cast<FileInterface*>(&this->m_handle_storage[0]));
230  return this->m_delegate.getHandle();
231 }
232 
236  crc = 0;
237  for (FwSizeType i = 0; i < std::numeric_limits<FwSizeType>::max(); i++) {
238  status = this->incrementalCrc(size);
239  // Break on eof or error
240  if ((size != FW_FILE_CHUNK_SIZE) || (status != File::OP_OK)) {
241  break;
242  }
243  }
244  // When successful, finalize the CRC
245  if (status == File::OP_OK) {
246  status = this->finalizeCrc(crc);
247  }
248  return status;
249 }
250 
254  if (OPEN_NO_MODE == this->m_mode) {
255  status = File::Status::NOT_OPENED;
256  } else if (OPEN_READ != this->m_mode) {
257  status = File::Status::INVALID_MODE;
258  } else {
259  // Read data without waiting for additional data to be available
260  status = this->read(this->m_crc_buffer, size, File::WaitType::NO_WAIT);
261  if (OP_OK == status) {
262  for (FwSizeType i = 0; i < size && i < FW_FILE_CHUNK_SIZE; i++) {
263  this->m_crc = static_cast<U32>(update_crc_32(this->m_crc, static_cast<CHAR>(this->m_crc_buffer[i])));
264  }
265  }
266  }
267  return status;
268 }
269 
272  crc = this->m_crc;
273  this->m_crc = File::INITIAL_CRC;
274  return status;
275 }
276 
278  const FwSizeType requested_size = size;
279  FW_ASSERT(&this->m_delegate == reinterpret_cast<FileInterface*>(&this->m_handle_storage[0]));
280  FW_ASSERT(buffer != nullptr);
281  FW_ASSERT(this->m_mode < Mode::MAX_OPEN_MODE);
282  // Check that the file is open before attempting operation
283  if (OPEN_NO_MODE == this->m_mode) {
284  size = 0;
285  return File::Status::NOT_OPENED;
286  } else if (OPEN_READ != this->m_mode) {
287  size = 0;
288  return File::Status::INVALID_MODE;
289  }
290  FwSizeType original_location = 0;
291  File::Status status = this->position(original_location);
292  if (status != Os::File::Status::OP_OK) {
293  size = 0;
294  (void)this->seek_absolute(original_location);
295  return status;
296  }
297  FwSizeType read = 0;
298  // Loop reading chunk by chunk
299  for (FwSizeType i = 0; i < size; i += read) {
300  // read in chunks to avoid large buffer allocations
301  FwSizeType current_chunk_size = std::min(size - i, static_cast<FwSizeType>(FW_FILE_CHUNK_SIZE));
302  read = current_chunk_size;
303  status = this->read(buffer + i, read, wait);
304  if (status != File::Status::OP_OK) {
305  return status;
306  }
307  // EOF break out now
308  if (read == 0) {
309  size = i;
311  }
312  // Loop from i to i + current_chunk_size looking for `\n`
313  for (FwSizeType j = i; j < (i + read); j++) {
314  // Newline seek back to after it, return the size read
315  if (buffer[j] == '\n') {
316  size = j + 1;
317  // Ensure that the computation worked and there is not overflow
318  FW_ASSERT(size <= requested_size);
319  FW_ASSERT(std::numeric_limits<FwSizeType>::max() - size >= original_location);
320  (void)this->seek_absolute(original_location + j + 1);
322  }
323  }
324  }
325  // Failed to find newline within data available
327 }
328 } // namespace Os
virtual Status open(const char *path, Mode mode, OverwriteType overwrite)=0
open file with supplied path and mode
Status incrementalCrc(FwSizeType &size)
calculate the CRC32 of the next section of data
Definition: File.cpp:251
base implementation of FileHandle
Definition: File.hpp:25
Operation succeeded.
Definition: Os.hpp:27
Status calculateCrc(U32 &crc)
calculate the CRC32 of the entire file
Definition: File.cpp:233
A catch-all for other errors. Have to look in implementation-specific code.
PlatformSizeType FwSizeType
File mode not yet selected.
Definition: File.hpp:31
Status preallocate(FwSizeType offset, FwSizeType length) override
pre-allocate file storage
Definition: File.cpp:126
Status position(FwSizeType &position_result) override
get file pointer position of the currently open file
Definition: File.cpp:116
Status seek_absolute(FwSizeType offset_unsigned)
seek the file pointer to the given offset absolutely with the full range
Definition: File.cpp:151
virtual void close()=0
close the file, if not opened then do nothing
Status size(FwSizeType &size_result) override
get size of currently open file
Definition: File.cpp:107
virtual const CHAR * toChar() const =0
Convert to a C-style char*.
PlatformSignedSizeType FwSignedSizeType
Os::FileInterface::Status open(const char *path, Mode mode)
open file with supplied path and mode
char CHAR
Definition: BasicTypes.h:59
virtual FileHandle * getHandle()=0
returns the raw file handle
virtual ~FileInterface()=default
unsigned long update_crc_32(unsigned long crc, char c)
Definition: lib_crc.c:272
virtual Status size(FwSizeType &size_result)=0
get size of currently open file
virtual Status flush()=0
flush file contents to storage
virtual Status seek(FwSignedSizeType offset, SeekType seekType)=0
seek the file pointer to the given offset
Status seek(FwSignedSizeType offset, SeekType seekType) override
seek the file pointer to the given offset
Definition: File.cpp:138
FileHandle * getHandle() override
returns the raw file handle
Definition: File.cpp:228
void close() override
close the file, if not opened then do nothing
Definition: File.cpp:93
Status write(const U8 *buffer, FwSizeType &size)
write data to this file from the supplied buffer bounded by size
Definition: File.cpp:209
virtual SizeType getCapacity() const =0
Return the size of the buffer.
uint8_t U8
8-bit unsigned integer
Definition: BasicTypes.h:53
Status read(U8 *buffer, FwSizeType &size)
read data from this file into supplied buffer bounded by size
Definition: File.cpp:190
Status flush() override
flush file contents to storage
Definition: File.cpp:178
static U32 min(const U32 a, const U32 b)
Definition: Checksum.cpp:16
virtual Status write(const U8 *buffer, FwSizeType &size, WaitType wait)=0
read data from this file into supplied buffer bounded by size
Status readline(U8 *buffer, FwSizeType &size, WaitType wait)
read a line from the file using \n as the delimiter
Definition: File.cpp:277
Operation was successful.
Definition: File.hpp:41
A read-only abstract superclass for StringBase.
Status finalizeCrc(U32 &crc)
finalize and retrieve the CRC value
Definition: File.cpp:270
Open file for reading.
Definition: File.hpp:32
~File() final
destructor
Definition: File.cpp:20
File()
constructor
Definition: File.cpp:16
static FileInterface * getDelegate(FileHandleStorage &aligned_placement_new_memory, const FileInterface *to_copy=nullptr)
provide a pointer to a file delegate object
Definition: DefaultFile.cpp:14
virtual Status preallocate(FwSizeType offset, FwSizeType length)=0
pre-allocate file storage
File & operator=(const File &other)
assignment operator that copies the internal representation
Definition: File.cpp:37
#define FW_ASSERT(...)
Definition: Assert.hpp:14
virtual Status position(FwSizeType &position_result)=0
get file pointer position of the currently open file
bool isOpen() const
determine if the file is open
Definition: File.cpp:101
virtual Status read(U8 *buffer, FwSizeType &size, WaitType wait)=0
read data from this file into supplied buffer bounded by size
FwSizeType string_length(const CHAR *source, FwSizeType buffer_size)
get the length of the source string
Definition: StringUtils.cpp:32