F´ Flight Software - C/C++ Documentation
A framework for building embedded system applications to NASA flight quality standards.
CRCChecker.cpp
Go to the documentation of this file.
1 // ======================================================================
2 // \title CRCChecker.cpp
3 // \author ortega
4 // \brief cpp file for a crc32 checker
5 //
6 // \copyright
7 // Copyright 2009-2020, by the California Institute of Technology.
8 // ALL RIGHTS RESERVED. United States Government Sponsorship
9 // acknowledged.
10 // ======================================================================
11 
12 #include <Fw/FPrimeBasicTypes.hpp>
13 #include <Fw/Types/Assert.hpp>
16 #include <Os/File.hpp>
17 #include <Os/FileSystem.hpp>
18 #include <Utils/CRCChecker.hpp>
19 #include <Utils/Hash/Hash.hpp>
20 
21 namespace Utils {
22 crc_stat_t create_checksum_file(const char* const fname) {
23  FW_ASSERT(fname != nullptr);
24 
25  FwSizeType i;
26  FwSizeType blocks;
27  FwSizeType remaining_bytes;
28  FwSizeType filesize;
29  Os::File f;
30  Os::FileSystem::Status fs_stat;
31  Os::File::Status stat;
32  Utils::Hash hash;
33  U32 checksum;
34  FwSizeType bytes_to_read;
35  FwSizeType bytes_to_write;
36  Fw::FileNameString hashFilename;
37  U8 block_data[CRC_FILE_READ_BLOCK];
38 
39  fs_stat = Os::FileSystem::getFileSize(fname, filesize);
40  if (fs_stat != Os::FileSystem::OP_OK) {
41  return FAILED_FILE_SIZE;
42  }
43 
44  // Open file
45  stat = f.open(fname, Os::File::OPEN_READ);
46  if (stat != Os::File::OP_OK) {
47  return FAILED_FILE_OPEN;
48  }
49 
50  // Read file
51  bytes_to_read = CRC_FILE_READ_BLOCK;
52  blocks = filesize / CRC_FILE_READ_BLOCK;
53  for (i = 0; i < blocks; i++) {
54  stat = f.read(block_data, bytes_to_read);
55  if (stat != Os::File::OP_OK || bytes_to_read != CRC_FILE_READ_BLOCK) {
56  f.close();
57  return FAILED_FILE_READ;
58  }
59 
60  hash.update(block_data, bytes_to_read);
61  }
62 
63  remaining_bytes = filesize % CRC_FILE_READ_BLOCK;
64  bytes_to_read = remaining_bytes;
65  if (remaining_bytes > 0) {
66  stat = f.read(block_data, bytes_to_read);
67  if (stat != Os::File::OP_OK || bytes_to_read != remaining_bytes) {
68  f.close();
69  return FAILED_FILE_READ;
70  }
71 
72  hash.update(block_data, remaining_bytes);
73  }
74 
75  // close file
76  f.close();
77 
78  // generate checksum
79  hash.finalize(checksum);
80 
81  // open checksum file. The filename is caller-supplied input: an overlong name is a reportable
82  // failure, not a coding error, so it must not assert.
83  Fw::FormatStatus formatStatus = hashFilename.format("%s%s", fname, HASH_EXTENSION_STRING);
84  if (formatStatus != Fw::FormatStatus::SUCCESS) {
86  }
87 
88  stat = f.open(hashFilename.toChar(), Os::File::OPEN_WRITE);
89  if (stat != Os::File::OP_OK) {
90  return FAILED_FILE_CRC_OPEN;
91  }
92 
93  // Write checksum file. Serialize the value rather than writing the raw U32 bytes so that the
94  // file contents do not depend on the endianness of the processor.
95  U8 checksum_data[sizeof(checksum)] = {};
96  Fw::SerialBuffer checksum_buffer(checksum_data, sizeof(checksum_data));
97  Fw::SerializeStatus ser_stat = checksum_buffer.serializeFrom(checksum);
98  FW_ASSERT(Fw::FW_SERIALIZE_OK == ser_stat, static_cast<FwAssertArgType>(ser_stat));
99 
100  bytes_to_write = checksum_buffer.getSize();
101  stat = f.write(checksum_buffer.getBuffAddr(), bytes_to_write);
102  if (stat != Os::File::OP_OK || sizeof(checksum) != bytes_to_write) {
103  f.close();
104  return FAILED_FILE_CRC_WRITE;
105  }
106 
107  // close checksum file
108  f.close();
109 
110  return PASSED_FILE_CRC_WRITE;
111 }
112 
113 crc_stat_t read_crc32_from_file(const char* const fname, U32& checksum_from_file) {
114  Os::File f;
115  Os::File::Status stat;
116  Fw::FileNameString hashFilename;
117  FW_ASSERT(fname != nullptr);
118  // open checksum file. See create_checksum_file(): overlong names are reported, not asserted.
119  Fw::FormatStatus formatStatus = hashFilename.format("%s%s", fname, HASH_EXTENSION_STRING);
120  if (formatStatus != Fw::FormatStatus::SUCCESS) {
122  }
123 
124  stat = f.open(hashFilename.toChar(), Os::File::OPEN_READ);
125  if (stat != Os::File::OP_OK) {
126  return FAILED_FILE_CRC_OPEN;
127  }
128 
129  // Read checksum file
130  U8 checksum_data[sizeof(checksum_from_file)] = {};
131  FwSizeType checksum_from_file_size = static_cast<FwSizeType>(sizeof(checksum_from_file));
132  stat = f.read(checksum_data, checksum_from_file_size);
133  if (stat != Os::File::OP_OK || checksum_from_file_size != sizeof(checksum_from_file)) {
134  f.close();
135  return FAILED_FILE_CRC_READ;
136  }
137 
138  // Deserialize the value to match the serialized form written by create_checksum_file
139  Fw::SerialBuffer checksum_buffer(checksum_data, sizeof(checksum_data));
140  checksum_buffer.fill();
141  Fw::SerializeStatus ser_stat = checksum_buffer.deserializeTo(checksum_from_file);
142  FW_ASSERT(Fw::FW_SERIALIZE_OK == ser_stat, static_cast<FwAssertArgType>(ser_stat));
143 
144  // close checksum file
145  f.close();
146  return PASSED_FILE_CRC_CHECK;
147 }
148 
149 crc_stat_t verify_checksum(const char* const fname, U32& expected, U32& actual) {
150  FW_ASSERT(fname != nullptr);
151 
152  FwSizeType i;
153  FwSizeType blocks;
154  FwSizeType remaining_bytes;
155  FwSizeType filesize;
156  Os::File f;
157  Os::FileSystem::Status fs_stat;
158  Os::File::Status stat;
159  Utils::Hash hash;
160  U32 checksum;
161  U32 checksum_from_file;
162  FwSizeType bytes_to_read;
163  U8 block_data[CRC_FILE_READ_BLOCK];
164 
165  fs_stat = Os::FileSystem::getFileSize(fname, filesize);
166  if (fs_stat != Os::FileSystem::OP_OK) {
167  return FAILED_FILE_SIZE;
168  }
169 
170  // Open file
171  stat = f.open(fname, Os::File::OPEN_READ);
172  if (stat != Os::File::OP_OK) {
173  return FAILED_FILE_OPEN;
174  }
175 
176  // Read file
177  bytes_to_read = CRC_FILE_READ_BLOCK;
178  blocks = filesize / CRC_FILE_READ_BLOCK;
179  for (i = 0; i < blocks; i++) {
180  stat = f.read(block_data, bytes_to_read);
181  if (stat != Os::File::OP_OK || bytes_to_read != CRC_FILE_READ_BLOCK) {
182  f.close();
183  return FAILED_FILE_READ;
184  }
185 
186  hash.update(block_data, static_cast<FwSizeType>(bytes_to_read));
187  }
188 
189  remaining_bytes = filesize % CRC_FILE_READ_BLOCK;
190  bytes_to_read = remaining_bytes;
191  if (remaining_bytes > 0) {
192  stat = f.read(block_data, bytes_to_read);
193  if (stat != Os::File::OP_OK || bytes_to_read != remaining_bytes) {
194  f.close();
195  return FAILED_FILE_READ;
196  }
197 
198  hash.update(block_data, remaining_bytes);
199  }
200 
201  // close file
202  f.close();
203  // generate checksum
204  hash.finalize(checksum);
205 
206  crc_stat_t crcstat = read_crc32_from_file(fname, checksum_from_file);
207  if (crcstat != PASSED_FILE_CRC_CHECK) {
208  return crcstat;
209  }
210 
211  // compare checksums
212  if (checksum != checksum_from_file) {
213  expected = checksum_from_file;
214  actual = checksum;
215  return FAILED_FILE_CRC_CHECK;
216  }
217 
218  expected = checksum_from_file;
219  actual = checksum;
220  return PASSED_FILE_CRC_CHECK;
221 }
222 
223 } // namespace Utils
#define HASH_EXTENSION_STRING
Definition: Crc32.hpp:33
void update(const void *const data, const FwSizeType len)
Definition: HashImpl.cpp:34
Serialization/Deserialization operation was successful.
A variable-length serializable buffer.
PlatformSizeType FwSizeType
Serializable::SizeType getSize() const override
Get current buffer size.
static const FwSignedSizeType CRC_FILE_READ_BLOCK
Definition: CRCChecker.hpp:20
SerializeStatus deserializeTo(U8 &val, Endianness mode=Endianness::BIG) override
Deserialize an 8-bit unsigned integer value.
void fill()
Fill the buffer to capacity with preexisting data.
Open file for writing.
Definition: File.hpp:35
SerializeStatus serializeFrom(U8 val, Endianness mode=Endianness::BIG) override
Serialize an 8-bit unsigned integer value.
SerializeStatus
forward declaration for string
crc_stat_t create_checksum_file(const char *const fname)
Definition: CRCChecker.cpp:22
Os::FileInterface::Status open(const char *path, Mode mode)
open file with supplied path and mode
Definition: File.cpp:50
crc_stat_t read_crc32_from_file(const char *const fname, U32 &checksum_from_file)
Definition: CRCChecker.cpp:113
U8 * getBuffAddr()
Get buffer address for data filling (non-const version)
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
A generic interface for creating and comparing hash values.
Definition: Hash.hpp:24
const char * toChar() const
Convert to a C-style char*.
crc_stat_t verify_checksum(const char *const fname, U32 &expected, U32 &actual)
Definition: CRCChecker.cpp:149
FormatStatus format(const CHAR *formatString,...)
write formatted string to buffer
Definition: StringBase.cpp:58
uint8_t U8
8-bit unsigned integer
Definition: BasicTypes.h:54
static Status getFileSize(const char *path, FwSizeType &size)
Get the size of the file (in bytes) at the specified path.
Definition: FileSystem.cpp:227
Status read(U8 *buffer, FwSizeType &size)
read data from this file into supplied buffer bounded by size
Definition: File.cpp:194
Operation was successful.
Definition: File.hpp:42
Open file for reading.
Definition: File.hpp:33
filename + hash extension does not fit in Fw::FileNameString
Definition: CRCChecker.hpp:33
Operation was successful.
Definition: FileSystem.hpp:24
void finalize(HashBuffer &buffer) const
Definition: HashImpl.cpp:40
#define FW_ASSERT(...)
Definition: Assert.hpp:14
FormatStatus
status of string format calls
Definition: format.hpp:18