fprime/Os/ValidateFileCommon.cpp
M Starch 58c21418aa
Issue 2457 (#2502)
* Os::File refactor: open w/ basic stub, posix UTs

* Refactoring Os::File for all methods, less UTs

* Adding rules-based common tests

* Fixing posix file for common UTs

* Adding WriteRead and WriteReadSeek tests

* Working random tests

* Working randomized tests and stub testing

* Fixing PrmDb unit tests

* Updating files to used FwSignedSizeType

* Factoring out the synthetic file system

* Initial work on CmdSequencer UTs

* Fixing linux implementation

* Newlines at end of file

* sp

* Static analysis checks

* Changing API to use enums

* Refactoring for proper class tree

* CmdSequencer UTs - WIP

* CmdSequencer UTs work

* Adding copy constructor functionality

* Spelling and static analysis fixes

* Copy constructor/assignment operator UTs and fixes

* Initial CRC work

* Working CRC and FPP models

* Minor UT fixes

* Correcting CMake choices implementation

* MAking implementation choices real dependencies

* Fixing implementation to use source files

* Fixing posix file read/write permissions

* Allowing None implementations

* Fixed CI breakages

* Fixing MyRules.hpp formatting

* Minor CRC unit test fix

* Removing direct write support

* Changing get delegate to static method of interface

* Replacing old comments with new comments

* Fixing friend regression

* Review fixes

* Fixing serialization method usages

* Review fixes

* Fixing RPI build

* Fixing FwBuffSizeType overflow

* Fixing review comment

* Renaming FwExternalSize -> FwSizeStoreType
2024-02-28 11:25:19 -08:00

230 lines
7.6 KiB
C++

#include <Os/ValidateFile.hpp>
#include <Os/File.hpp>
#include <Utils/Hash/Hash.hpp>
#include <Os/FileSystem.hpp>
namespace Os {
File::Status computeHash(const char* fileName, Utils::HashBuffer &hashBuffer) {
File::Status status;
// Open file:
File file;
status = file.open(fileName, File::OPEN_READ);
if( File::OP_OK != status ) {
return status;
}
// Get the file size:
FileSystem::Status fs_status;
FwSignedSizeType fileSize = 0;
fs_status = FileSystem::getFileSize(fileName, fileSize); //!< gets the size of the file (in bytes) at location path
// fileSize will be used as a NATIVE_INT_TYPE below and thus must cast cleanly to that type
if( FileSystem::OP_OK != fs_status) {
return File::BAD_SIZE;
}
const NATIVE_INT_TYPE max_itr = static_cast<NATIVE_INT_TYPE>(fileSize/VFILE_HASH_CHUNK_SIZE + 1);
// Read all data from file and update hash:
Utils::Hash hash;
hash.init();
U8 buffer[VFILE_HASH_CHUNK_SIZE];
FwSignedSizeType size = 0;
FwSignedSizeType cnt = 0;
while( cnt <= max_itr ) {
// Read out chunk from file:
size = sizeof(buffer);
status = file.read(buffer, size, Os::File::WaitType::NO_WAIT);
if( File::OP_OK != status ) {
return status;
}
// If end of file, break:
if( size == 0 ) {
break;
}
// Add chunk to hash calculation:
hash.update(&buffer, size);
cnt++;
}
file.close();
// We should not have left the loop because of cnt > max_itr:
FW_ASSERT(size == 0);
FW_ASSERT(cnt <= max_itr);
// Calculate hash:
Utils::HashBuffer computedHashBuffer;
hash.final(computedHashBuffer);
hashBuffer = computedHashBuffer;
return status;
}
File::Status readHash(const char* hashFileName, Utils::HashBuffer &hashBuffer) {
File::Status status;
// Open hash file:
File hashFile;
status = hashFile.open(hashFileName, File::OPEN_READ);
if( File::OP_OK != status ) {
return status;
}
// Read hash from checksum file:
unsigned char savedHash[HASH_DIGEST_LENGTH];
FwSignedSizeType size = hashBuffer.getBuffCapacity();
status = hashFile.read(savedHash, size);
if( File::OP_OK != status ) {
return status;
}
if( size != static_cast<NATIVE_INT_TYPE>(hashBuffer.getBuffCapacity()) ) {
return File::BAD_SIZE;
}
hashFile.close();
// Return the hash buffer:
Utils::HashBuffer savedHashBuffer(savedHash, size);
hashBuffer = savedHashBuffer;
return status;
}
File::Status writeHash(const char* hashFileName, Utils::HashBuffer hashBuffer) {
// Open hash file:
File hashFile;
File::Status status;
status = hashFile.open(hashFileName, File::OPEN_WRITE);
if( File::OP_OK != status ) {
return status;
}
// Write out the hash
FwSignedSizeType size = hashBuffer.getBuffLength();
status = hashFile.write(hashBuffer.getBuffAddr(), size, Os::File::WaitType::NO_WAIT);
if( File::OP_OK != status ) {
return status;
}
if( size != static_cast<NATIVE_INT_TYPE>(hashBuffer.getBuffLength()) ) {
return File::BAD_SIZE;
}
hashFile.close();
return status;
}
// Enum and function for translating from a status to a validation status:
typedef enum {
FileType,
HashFileType
} StatusFileType;
ValidateFile::Status translateStatus(File::Status status, StatusFileType type) {
switch (type) {
case FileType:
switch (status) {
case File::OP_OK:
return ValidateFile::VALIDATION_OK;
case File::DOESNT_EXIST:
return ValidateFile::FILE_DOESNT_EXIST;
case File::NO_SPACE:
return ValidateFile::NO_SPACE;
case File::NO_PERMISSION:
return ValidateFile::FILE_NO_PERMISSION;
case File::BAD_SIZE:
return ValidateFile::FILE_BAD_SIZE;
case File::NOT_OPENED:
return ValidateFile::OTHER_ERROR;
case File::OTHER_ERROR:
return ValidateFile::OTHER_ERROR;
default:
FW_ASSERT(0, status);
}
break;
case HashFileType:
switch (status) {
case File::OP_OK:
return ValidateFile::VALIDATION_OK;
case File::DOESNT_EXIST:
return ValidateFile::VALIDATION_FILE_DOESNT_EXIST;
case File::NO_SPACE:
return ValidateFile::NO_SPACE;
case File::NO_PERMISSION:
return ValidateFile::VALIDATION_FILE_NO_PERMISSION;
case File::BAD_SIZE:
return ValidateFile::VALIDATION_FILE_BAD_SIZE;
case File::NOT_OPENED:
return ValidateFile::OTHER_ERROR;
case File::OTHER_ERROR:
return ValidateFile::OTHER_ERROR;
default:
FW_ASSERT(0, status);
}
break;
default:
FW_ASSERT(0, type);
}
return ValidateFile::OTHER_ERROR;
}
ValidateFile::Status ValidateFile::validate(const char* fileName, const char* hashFileName) {
Utils::HashBuffer hashBuffer; // pass by reference - final value is unused
return validate(fileName, hashFileName, hashBuffer);
}
ValidateFile::Status ValidateFile::validate(const char* fileName, const char* hashFileName, Utils::HashBuffer &hashBuffer) {
File::Status status;
// Read the hash file:
Utils::HashBuffer savedHash;
status = readHash(hashFileName, savedHash);
if( File::OP_OK != status ) {
return translateStatus(status, HashFileType);
}
// Compute the file's hash:
Utils::HashBuffer computedHash;
status = computeHash(fileName, computedHash);
if( File::OP_OK != status ) {
return translateStatus(status, FileType);
}
// Compare hashes and return:
if( savedHash != computedHash ){
return ValidateFile::VALIDATION_FAIL;
}
hashBuffer = savedHash;
return ValidateFile::VALIDATION_OK;
}
ValidateFile::Status ValidateFile::createValidation(const char* fileName, const char* hashFileName, Utils::HashBuffer &hashBuffer) {
File::Status status;
// Compute the file's hash:
status = computeHash(fileName, hashBuffer);
if( File::OP_OK != status ) {
return translateStatus(status, FileType);
}
status = writeHash(hashFileName, hashBuffer);
if( File::OP_OK != status ) {
return translateStatus(status, HashFileType);
}
return ValidateFile::VALIDATION_OK;
}
ValidateFile::Status ValidateFile::createValidation(const char* fileName, const char* hashFileName) {
Utils::HashBuffer hashBuffer; // pass by reference - final value is unused
return createValidation(fileName, hashFileName, hashBuffer);
}
}