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