fprime/Os/ValidateFileCommon.cpp
M Starch f912e1bd75
Issue 3285 reducing signed size type in os file (#3402)
* Remove FwSignedSizeType from file

* Restoring FwSignedSizeType to seek offsets

* Fixing usages and UTs

* Fixes on Linux

* CI fix

* CI round 3

* CI rev 4

* Fixing code scan errors

* Review fixes - pt 1

* Failed to save
2025-03-28 11:47:07 -07:00

229 lines
7.5 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;
FwSizeType fileSize = 0;
fs_status = FileSystem::getFileSize(fileName, fileSize); //!< gets the size of the file (in bytes) at location path
if( FileSystem::OP_OK != fs_status) {
return File::BAD_SIZE;
}
const FwSizeType max_itr = (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];
FwSizeType size = 0;
FwSizeType 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, static_cast<FwSizeType>(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];
FwSizeType size = static_cast<FwSizeType>(hashBuffer.getBuffCapacity());
status = hashFile.read(savedHash, size);
if( File::OP_OK != status ) {
return status;
}
if(static_cast<FwSizeType>(size) != hashBuffer.getBuffCapacity()) {
return File::BAD_SIZE;
}
hashFile.close();
// Return the hash buffer:
Utils::HashBuffer savedHashBuffer(savedHash, static_cast<FwSizeType>(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
FwSizeType size = static_cast<FwSizeType>(hashBuffer.getBuffLength());
status = hashFile.write(hashBuffer.getBuffAddr(), size, Os::File::WaitType::NO_WAIT);
if( File::OP_OK != status ) {
return status;
}
if(static_cast<FwSizeType>(size) != 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);
}
}