mirror of
https://github.com/nasa/fprime.git
synced 2025-12-12 07:43:50 -06:00
* bugfixes to uts. the old way was generating out of range offsets * bugfixes * adding more helpful messages and bugfix to ut for when mode is OPEN_APPEND * removed unnecessary prints * ci fixes and updates based on review * fix for static analyzer * sp * should appease ci * append moves the file pointer before write not on open * typo * cleaned up code * open with append will still have the state position to 0
275 lines
11 KiB
C++
275 lines
11 KiB
C++
// ======================================================================
|
|
// \title Os/test/ut/file/SyntheticFileSystem.cpp
|
|
// \brief standard template library driven synthetic file system implementation
|
|
// ======================================================================
|
|
#include "Os/test/ut/file/SyntheticFileSystem.hpp"
|
|
#include "Fw/Types/Assert.hpp"
|
|
|
|
namespace Os {
|
|
namespace Test {
|
|
|
|
SyntheticFile::~SyntheticFile() {
|
|
this->close();
|
|
}
|
|
|
|
SyntheticFileSystem::OpenData SyntheticFileSystem::open(const CHAR* char_path, const Os::File::Mode open_mode, const File::OverwriteType overwrite) {
|
|
SyntheticFileSystem::OpenData return_value;
|
|
std::string path = char_path;
|
|
bool exists = (this->m_filesystem.count(path) > 0);
|
|
|
|
// Error case: read on file that does not exist
|
|
if ((not exists) && (Os::File::Mode::OPEN_READ == open_mode)) {
|
|
return_value.status = Os::File::Status::DOESNT_EXIST;
|
|
}
|
|
// Error case: create on existing file without overwrite
|
|
else if (exists and (not overwrite) && (open_mode == Os::File::Mode::OPEN_CREATE)) {
|
|
return_value.status = Os::File::Status::FILE_EXISTS;
|
|
}
|
|
// Case where file should be opened correctly
|
|
else {
|
|
const bool truncate = (Os::File::Mode::OPEN_CREATE == open_mode) && overwrite;
|
|
|
|
// Add new shadow file data when the file is new
|
|
if (not exists) {
|
|
this->m_filesystem[path] = std::make_shared<SyntheticFileData>();
|
|
}
|
|
return_value.file = this->m_filesystem[path];
|
|
return_value.status = Os::File::Status::OP_OK;
|
|
|
|
// Set file properties
|
|
if (truncate) {
|
|
return_value.file->m_data.clear();
|
|
}
|
|
|
|
return_value.file->m_pointer = 0;
|
|
|
|
return_value.file->m_mode = open_mode;
|
|
return_value.file->m_path = path;
|
|
// Checks on the shadow data to ensure consistency
|
|
FW_ASSERT(return_value.file->m_mode != Os::File::OPEN_NO_MODE);
|
|
FW_ASSERT(return_value.file->m_pointer == 0);
|
|
FW_ASSERT(return_value.file->m_path == path);
|
|
FW_ASSERT(not truncate || return_value.file->m_data.empty());
|
|
}
|
|
return return_value;
|
|
}
|
|
|
|
bool SyntheticFileSystem::exists(const CHAR* char_path) {
|
|
std::string path = char_path;
|
|
FW_ASSERT(this->m_filesystem.count(path) <= 1);
|
|
return this->m_filesystem.count(path) == 1;
|
|
}
|
|
|
|
void SyntheticFileSystem::remove(const CHAR* char_path) {
|
|
std::string path = char_path;
|
|
this->m_filesystem.erase(path);
|
|
}
|
|
|
|
std::unique_ptr<SyntheticFileSystem> SyntheticFile::s_file_system = std::unique_ptr<SyntheticFileSystem>(new SyntheticFileSystem());
|
|
|
|
void SyntheticFile::setFileSystem(std::unique_ptr<SyntheticFileSystem> new_file_system) {
|
|
s_file_system = std::move(new_file_system);
|
|
}
|
|
|
|
void SyntheticFile::remove(const CHAR* char_path) {
|
|
FW_ASSERT(s_file_system != nullptr);
|
|
s_file_system->remove(char_path);
|
|
}
|
|
|
|
File::Status SyntheticFile::open(const CHAR* char_path, const Os::File::Mode open_mode, const File::OverwriteType overwrite) {
|
|
SyntheticFileSystem::OpenData data = s_file_system->open(char_path, open_mode, overwrite);
|
|
if (data.status == Os::File::Status::OP_OK) {
|
|
this->m_data = data.file;
|
|
FW_ASSERT(this->m_data != nullptr);
|
|
}
|
|
return data.status;
|
|
}
|
|
|
|
void SyntheticFile::close() {
|
|
if (this->m_data != nullptr) {
|
|
this->m_data->m_mode = Os::File::Mode::OPEN_NO_MODE;
|
|
this->m_data->m_path.clear();
|
|
this->m_data->m_pointer = 0;
|
|
// Checks on the shadow data to ensure consistency
|
|
FW_ASSERT(this->m_data->m_mode == Os::File::Mode::OPEN_NO_MODE);
|
|
FW_ASSERT(this->m_data->m_path.empty());
|
|
FW_ASSERT(this->m_data->m_pointer == 0);
|
|
}
|
|
}
|
|
|
|
Os::File::Status SyntheticFile::read(U8* buffer, FwSizeType& size, WaitType wait) {
|
|
(void) wait;
|
|
FW_ASSERT(this->m_data != nullptr);
|
|
FW_ASSERT(buffer != nullptr);
|
|
FW_ASSERT(this->m_data->m_mode < Os::File::Mode::MAX_OPEN_MODE);
|
|
// Check that the file is open before attempting operation
|
|
if (Os::File::Mode::OPEN_NO_MODE == this->m_data->m_mode) {
|
|
size = 0;
|
|
return Os::File::Status::NOT_OPENED;
|
|
} else if (Os::File::Mode::OPEN_READ != this->m_data->m_mode) {
|
|
size = 0;
|
|
return Os::File::Status::INVALID_MODE;
|
|
}
|
|
std::vector<U8> output;
|
|
FwSizeType original_pointer = this->m_data->m_pointer;
|
|
FwSizeType original_size = static_cast<FwSizeType>(this->m_data->m_data.size());
|
|
// Check expected read bytes
|
|
FwSizeType i = 0;
|
|
for (i = 0; i < size; i++, this->m_data->m_pointer++) {
|
|
// End of file
|
|
if (this->m_data->m_pointer >= static_cast<FwSizeType>(this->m_data->m_data.size())) {
|
|
break;
|
|
}
|
|
buffer[i] = this->m_data->m_data.at(static_cast<std::vector<U8>::size_type>(this->m_data->m_pointer));
|
|
}
|
|
size = i;
|
|
// Checks on the shadow data to ensure consistency
|
|
FW_ASSERT(this->m_data->m_data.size() == static_cast<size_t>(original_size));
|
|
FW_ASSERT(this->m_data->m_pointer == ((original_pointer > original_size) ? original_pointer : FW_MIN(original_pointer + size, original_size)));
|
|
FW_ASSERT(size == ((original_pointer > original_size) ? 0 : FW_MIN(size, original_size - original_pointer)));
|
|
return Os::File::Status::OP_OK;
|
|
}
|
|
|
|
Os::File::Status SyntheticFile::write(const U8* buffer, FwSizeType& size, WaitType wait) {
|
|
(void) wait;
|
|
FW_ASSERT(this->m_data != nullptr);
|
|
FW_ASSERT(buffer != nullptr);
|
|
FW_ASSERT(this->m_data->m_mode < Os::File::Mode::MAX_OPEN_MODE);
|
|
// Check that the file is open before attempting operation
|
|
if (Os::File::Mode::OPEN_NO_MODE == this->m_data->m_mode) {
|
|
size = 0;
|
|
return Os::File::Status::NOT_OPENED;
|
|
} else if (Os::File::Mode::OPEN_READ == this->m_data->m_mode) {
|
|
size = 0;
|
|
return Os::File::Status::INVALID_MODE;
|
|
}
|
|
FwSizeType original_position = this->m_data->m_pointer;
|
|
FwSizeType original_size = static_cast<FwSizeType>(this->m_data->m_data.size());
|
|
const U8* write_data = reinterpret_cast<const U8*>(buffer);
|
|
|
|
// Appends seek to end before writing
|
|
if (Os::File::Mode::OPEN_APPEND == this->m_data->m_mode) {
|
|
this->m_data->m_pointer = static_cast<FwSizeType>(this->m_data->m_data.size());
|
|
}
|
|
|
|
// First add in zeros to account for a pointer past the end of the file
|
|
const FwSizeType zeros = (this->m_data->m_pointer < this->m_data->m_data.size()) ? 0 : this->m_data->m_pointer - this->m_data->m_data.size();
|
|
for (FwSizeType i = 0; i < zeros; i++) {
|
|
this->m_data->m_data.push_back(0);
|
|
}
|
|
// Interim checks to ensure zeroing performed correctly
|
|
FW_ASSERT(static_cast<size_t>(this->m_data->m_pointer) <= this->m_data->m_data.size());
|
|
FW_ASSERT(this->m_data->m_data.size() ==
|
|
static_cast<size_t>((Os::File::Mode::OPEN_APPEND == this->m_data->m_mode) ? original_size : FW_MAX(original_position, original_size)));
|
|
|
|
FwSizeType pre_write_position = this->m_data->m_pointer;
|
|
FwSizeType pre_write_size = static_cast<FwSizeType>(this->m_data->m_data.size());
|
|
|
|
// Next write data
|
|
FwSizeType i = 0;
|
|
for (i = 0; i < size; i++, this->m_data->m_pointer++) {
|
|
// Overwrite case
|
|
if (static_cast<size_t>(this->m_data->m_pointer) < this->m_data->m_data.size()) {
|
|
this->m_data->m_data.at(static_cast<std::vector<U8>::size_type>(this->m_data->m_pointer)) = write_data[i];
|
|
}
|
|
// Append case
|
|
else {
|
|
this->m_data->m_data.push_back(write_data[i]);
|
|
}
|
|
}
|
|
size = i;
|
|
// Checks on the shadow data to ensure consistency
|
|
FW_ASSERT(this->m_data->m_data.size() ==
|
|
static_cast<size_t>(FW_MAX(pre_write_position + size, pre_write_size)));
|
|
FW_ASSERT(this->m_data->m_pointer ==
|
|
((Os::File::Mode::OPEN_APPEND == this->m_data->m_mode) ? pre_write_size : pre_write_position) + size);
|
|
return Os::File::Status::OP_OK;
|
|
}
|
|
|
|
Os::File::Status SyntheticFile::seek(const FwSignedSizeType offset, const SeekType absolute) {
|
|
FW_ASSERT(this->m_data != nullptr);
|
|
Os::File::Status status = Os::File::Status::OP_OK;
|
|
// Cannot do a seek with a negative offset in absolute mode
|
|
FW_ASSERT(not absolute || offset >= 0);
|
|
FW_ASSERT(this->m_data->m_mode < Os::File::Mode::MAX_OPEN_MODE);
|
|
// Check that the file is open before attempting operation
|
|
if (Os::File::Mode::OPEN_NO_MODE == this->m_data->m_mode) {
|
|
status = Os::File::Status::NOT_OPENED;
|
|
} else {
|
|
if (absolute) {
|
|
this->m_data->m_pointer = static_cast<FwSizeType>(offset);
|
|
}
|
|
// Seek to < 0
|
|
else if ((offset < 0) && ((static_cast<FwSizeType>(-1 * offset) > this->m_data->m_pointer) || (offset == std::numeric_limits<FwSignedSizeType>::min()))) {
|
|
status = Os::File::Status::INVALID_ARGUMENT;
|
|
}
|
|
// Other negative offsets
|
|
else if (offset < 0) {
|
|
this->m_data->m_pointer -= static_cast<FwSizeType>(-1*offset);
|
|
}
|
|
// Overflow
|
|
else if ((std::numeric_limits<FwSizeType>::max() - this->m_data->m_pointer) < static_cast<FwSizeType>(offset)) {
|
|
status = Os::File::Status::BAD_SIZE;
|
|
}
|
|
else {
|
|
this->m_data->m_pointer += static_cast<FwSizeType>(offset);
|
|
}
|
|
}
|
|
return status;
|
|
}
|
|
|
|
Os::File::Status SyntheticFile::preallocate(const FwSizeType offset, const FwSizeType length) {
|
|
FW_ASSERT(this->m_data != nullptr);
|
|
Os::File::Status status = Os::File::Status::OP_OK;
|
|
FW_ASSERT(this->m_data->m_mode < Os::File::Mode::MAX_OPEN_MODE);
|
|
// Check that the file is open before attempting operation
|
|
if (Os::File::Mode::OPEN_NO_MODE == this->m_data->m_mode) {
|
|
status = Os::File::Status::NOT_OPENED;
|
|
} else if (Os::File::Mode::OPEN_READ == this->m_data->m_mode) {
|
|
status = Os::File::Status::INVALID_MODE;
|
|
} else {
|
|
const FwSizeType original_size = static_cast<FwSizeType>(this->m_data->m_data.size());
|
|
const FwSizeType new_length = offset + length;
|
|
// Loop from existing size to new size adding zeros
|
|
for (FwSizeType i = static_cast<FwSizeType>(this->m_data->m_data.size()); i < new_length; i++) {
|
|
this->m_data->m_data.push_back(0);
|
|
}
|
|
FW_ASSERT(this->m_data->m_data.size() == static_cast<size_t>(FW_MAX(offset + length, original_size)));
|
|
}
|
|
return status;
|
|
}
|
|
|
|
Os::File::Status SyntheticFile::flush() {
|
|
FW_ASSERT(this->m_data != nullptr);
|
|
Os::File::Status status = Os::File::Status::OP_OK;
|
|
FW_ASSERT(this->m_data->m_mode < Os::File::Mode::MAX_OPEN_MODE);
|
|
// Check that the file is open before attempting operation
|
|
if (Os::File::Mode::OPEN_NO_MODE == this->m_data->m_mode) {
|
|
status = Os::File::Status::NOT_OPENED;
|
|
} else if (Os::File::Mode::OPEN_READ == this->m_data->m_mode) {
|
|
status = Os::File::Status::INVALID_MODE;
|
|
}
|
|
return status;
|
|
}
|
|
|
|
Os::File::Status SyntheticFile::position(FwSizeType &position) {
|
|
position = this->m_data->m_pointer;
|
|
return Os::File::OP_OK;
|
|
}
|
|
|
|
Os::File::Status SyntheticFile::size(FwSizeType &size) {
|
|
size = static_cast<FwSizeType>(this->m_data->m_data.size());
|
|
return Os::File::OP_OK;
|
|
}
|
|
|
|
FileHandle* SyntheticFile::getHandle() {
|
|
return this->m_data.get();
|
|
}
|
|
|
|
bool SyntheticFile::exists(const CHAR* path) {
|
|
return s_file_system->exists(path);
|
|
}
|
|
|
|
} // namespace Test
|
|
} // namespace Os
|