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