Editor implementation update for VPD-Manager app.
This commit updates the implementaion logic of reading VPD file
for vpd keyword update using VPD-Manager app.
In order to improve the efficiency, full vpd file will be read
in a single call instead of multiple blocks using multiple call.
Signed-off-by: Sunny Srivastava <sunnsr25@in.ibm.com>
Change-Id: Ibf4c6ba1cfb1b098a542be7ade7f0046e444abbe
diff --git a/const.hpp b/const.hpp
index 5169987..1fc24cc 100644
--- a/const.hpp
+++ b/const.hpp
@@ -19,6 +19,7 @@
using ECCOffset = uint16_t;
using ECCLength = uint16_t;
using LE2ByteData = uint16_t;
+using DataOffset = uint16_t;
static constexpr auto MAC_ADDRESS_LEN_BYTES = 6;
static constexpr auto LAST_KW = "PF";
diff --git a/vpd-manager/editor_impl.cpp b/vpd-manager/editor_impl.cpp
index 3bad2f8..b116d2d 100644
--- a/vpd-manager/editor_impl.cpp
+++ b/vpd-manager/editor_impl.cpp
@@ -1,5 +1,6 @@
#include "editor_impl.hpp"
+#include "parser.hpp"
#include "utils.hpp"
#include <fstream>
@@ -67,7 +68,7 @@
throw std::runtime_error("Record not found");
}
-void EditorImpl::updateData(Binary kwdData)
+void EditorImpl::updateData(const Binary& kwdData)
{
std::size_t lengthToUpdate = kwdData.size() <= thisRecord.kwdDataLength
? kwdData.size()
@@ -77,30 +78,42 @@
auto end = iteratorToNewdata;
std::advance(end, lengthToUpdate);
+ // update data in file buffer as it will be needed to update ECC
+ // avoiding extra stream operation here
+ auto iteratorToKWdData = vpdFile.begin();
+ std::advance(iteratorToKWdData, thisRecord.kwDataOffset);
+ std::copy(iteratorToNewdata, end, iteratorToKWdData);
+
+ // update data in EEPROM as well. As we will not write complete file back
+ vpdFileStream.seekg(thisRecord.kwDataOffset, std::ios::beg);
+ iteratorToNewdata = kwdData.cbegin();
std::copy(iteratorToNewdata, end,
std::ostreambuf_iterator<char>(vpdFileStream));
+
+ // get a hold to new data in case encoding is needed
+ thisRecord.kwdUpdatedData.resize(thisRecord.kwdDataLength);
+ auto itrToKWdData = vpdFile.cbegin();
+ std::advance(itrToKWdData, thisRecord.kwDataOffset);
+ auto kwdDataEnd = itrToKWdData;
+ std::advance(kwdDataEnd, thisRecord.kwdDataLength);
+ std::copy(itrToKWdData, kwdDataEnd, thisRecord.kwdUpdatedData.begin());
}
void EditorImpl::checkRecordForKwd()
{
RecordOffset recOffset = thisRecord.recOffset;
- // Jump to record name
- auto nameOffset = recOffset + sizeof(RecordId) + sizeof(RecordSize) +
- // Skip past the RT keyword, which contains
- // the record name.
- lengths::KW_NAME + sizeof(KwSize);
+ // Amount to skip for record ID, size, and the RT keyword
+ constexpr auto skipBeg = sizeof(RecordId) + sizeof(RecordSize) +
+ lengths::KW_NAME + sizeof(KwSize);
- vpdFileStream.seekg(nameOffset + lengths::RECORD_NAME, std::ios::beg);
+ auto iterator = vpdFile.cbegin();
+ std::advance(iterator, recOffset + skipBeg + lengths::RECORD_NAME);
- (thisRecord.recData).resize(thisRecord.recSize);
- vpdFileStream.read(reinterpret_cast<char*>((thisRecord.recData).data()),
- thisRecord.recSize);
-
- auto iterator = (thisRecord.recData).cbegin();
- auto end = (thisRecord.recData).cend();
-
+ auto end = iterator;
+ std::advance(end, thisRecord.recSize);
std::size_t dataLength = 0;
+
while (iterator < end)
{
// Note keyword name
@@ -130,13 +143,8 @@
if (thisRecord.recKWd == kw)
{
- // We're done
- std::size_t kwdOffset =
- std::distance((thisRecord.recData).cbegin(), iterator);
- vpdFileStream.seekp(nameOffset + lengths::RECORD_NAME + kwdOffset,
- std::ios::beg);
+ thisRecord.kwDataOffset = std::distance(vpdFile.cbegin(), iterator);
thisRecord.kwdDataLength = dataLength;
-
return;
}
@@ -149,51 +157,47 @@
void EditorImpl::updateRecordECC()
{
- vpdFileStream.seekp(thisRecord.recECCoffset, std::ios::beg);
+ auto itrToRecordData = vpdFile.cbegin();
+ std::advance(itrToRecordData, thisRecord.recOffset);
- (thisRecord.recEccData).resize(thisRecord.recECCLength);
- vpdFileStream.read(reinterpret_cast<char*>((thisRecord.recEccData).data()),
- thisRecord.recECCLength);
-
- auto recPtr = (thisRecord.recData).cbegin();
- auto recEccPtr = (thisRecord.recEccData).cbegin();
+ auto itrToRecordECC = vpdFile.cbegin();
+ std::advance(itrToRecordECC, thisRecord.recECCoffset);
auto l_status = vpdecc_create_ecc(
- const_cast<uint8_t*>(&recPtr[0]), thisRecord.recSize,
- const_cast<uint8_t*>(&recEccPtr[0]), &thisRecord.recECCLength);
+ const_cast<uint8_t*>(&itrToRecordData[0]), thisRecord.recSize,
+ const_cast<uint8_t*>(&itrToRecordECC[0]), &thisRecord.recECCLength);
if (l_status != VPD_ECC_OK)
{
throw std::runtime_error("Ecc update failed");
}
- auto end = (thisRecord.recEccData).cbegin();
+ auto end = itrToRecordECC;
std::advance(end, thisRecord.recECCLength);
- std::copy((thisRecord.recEccData).cbegin(), end,
+ vpdFileStream.seekp(thisRecord.recECCoffset, std::ios::beg);
+ std::copy(itrToRecordECC, end,
std::ostreambuf_iterator<char>(vpdFileStream));
}
auto EditorImpl::getValue(offsets::Offsets offset)
{
- Byte data = 0;
- vpdFileStream.seekg(offset, std::ios::beg)
- .get(*(reinterpret_cast<char*>(&data)));
- LE2ByteData lowByte = data;
-
- vpdFileStream.seekg(offset + 1, std::ios::beg)
- .get(*(reinterpret_cast<char*>(&data)));
- LE2ByteData highByte = data;
+ auto itr = vpdFile.cbegin();
+ std::advance(itr, offset);
+ LE2ByteData lowByte = *itr;
+ LE2ByteData highByte = *(itr + 1);
lowByte |= (highByte << 8);
return lowByte;
}
-void EditorImpl::checkECC(const Binary& tocRecData, const Binary& tocECCData,
+void EditorImpl::checkECC(Binary::const_iterator& itrToRecData,
+ Binary::const_iterator& itrToECCData,
RecordLength recLength, ECCLength eccLength)
{
auto l_status =
- vpdecc_check_data(const_cast<uint8_t*>(&tocRecData[0]), recLength,
- const_cast<uint8_t*>(&tocECCData[0]), eccLength);
+ vpdecc_check_data(const_cast<uint8_t*>(&itrToRecData[0]), recLength,
+ const_cast<uint8_t*>(&itrToECCData[0]), eccLength);
+
if (l_status != VPD_ECC_OK)
{
throw std::runtime_error("Ecc check failed for VTOC");
@@ -214,42 +218,36 @@
// read TOC ecc length
ECCLength tocECCLength = getValue(offsets::VTOC_ECC_LEN);
- // read toc record data
- Binary vtocRecord(tocLength);
- vpdFileStream.seekg(tocOffset, std::ios::beg);
- vpdFileStream.read(reinterpret_cast<char*>(vtocRecord.data()), tocLength);
+ auto itrToRecord = vpdFile.cbegin();
+ std::advance(itrToRecord, tocOffset);
- // read toc ECC for ecc check
- Binary vtocECC(tocECCLength);
- vpdFileStream.seekg(tocECCOffset, std::ios::beg);
- vpdFileStream.read(reinterpret_cast<char*>(vtocECC.data()), tocECCLength);
+ auto iteratorToECC = vpdFile.cbegin();
+ std::advance(iteratorToECC, tocECCOffset);
- auto iterator = vtocRecord.cbegin();
+ // validate ecc for the record
+ checkECC(itrToRecord, iteratorToECC, tocLength, tocECCLength);
// to get to the record name.
- std::advance(iterator, sizeof(RecordId) + sizeof(RecordSize) +
- // Skip past the RT keyword, which contains
- // the record name.
- lengths::KW_NAME + sizeof(KwSize));
+ std::advance(itrToRecord, sizeof(RecordId) + sizeof(RecordSize) +
+ // Skip past the RT keyword, which contains
+ // the record name.
+ lengths::KW_NAME + sizeof(KwSize));
- std::string recordName(iterator, iterator + lengths::RECORD_NAME);
+ std::string recordName(itrToRecord, itrToRecord + lengths::RECORD_NAME);
if ("VTOC" != recordName)
{
throw std::runtime_error("VTOC record not found");
}
- // validate ecc for the record
- checkECC(vtocRecord, vtocECC, tocLength, tocECCLength);
-
// jump to length of PT kwd
- std::advance(iterator, lengths::RECORD_NAME + lengths::KW_NAME);
+ std::advance(itrToRecord, lengths::RECORD_NAME + lengths::KW_NAME);
// Note size of PT
- Byte ptLen = *iterator;
- std::advance(iterator, 1);
+ Byte ptLen = *itrToRecord;
+ std::advance(itrToRecord, 1);
- checkPTForRecord(iterator, ptLen);
+ checkPTForRecord(itrToRecord, ptLen);
}
void EditorImpl::updateKeyword(const Binary& kwdData)
@@ -261,17 +259,35 @@
throw std::runtime_error("unable to open vpd file to edit");
}
- // process VTOC for PTT rkwd
- readVTOC();
+ Binary completeVPDFile((std::istreambuf_iterator<char>(vpdFileStream)),
+ std::istreambuf_iterator<char>());
+ vpdFile = completeVPDFile;
- // check record for keywrod
- checkRecordForKwd();
+ auto iterator = vpdFile.cbegin();
+ std::advance(iterator, IPZ_DATA_START);
- // update the data to the file
- updateData(kwdData);
+ Byte vpdType = *iterator;
+ if (vpdType == KW_VAL_PAIR_START_TAG)
+ {
+ openpower::vpd::keyword::editor::processHeader(
+ std::move(completeVPDFile));
- // update the ECC data for the record once data has been updated
- updateRecordECC();
+ // process VTOC for PTT rkwd
+ readVTOC();
+
+ // check record for keywrod
+ checkRecordForKwd();
+
+ // update the data to the file
+ updateData(kwdData);
+
+ // update the ECC data for the record once data has been updated
+ updateRecordECC();
+
+ return;
+ }
+
+ throw std::runtime_error("Invalid VPD file type");
}
} // namespace editor
diff --git a/vpd-manager/editor_impl.hpp b/vpd-manager/editor_impl.hpp
index 997bf85..70596a4 100644
--- a/vpd-manager/editor_impl.hpp
+++ b/vpd-manager/editor_impl.hpp
@@ -70,18 +70,19 @@
void readVTOC();
/** @brief validate ecc data for the VTOC record
- * @param[in] tocRecData - VTOC record data
- * @param[in] tocECCData - VTOC ECC data
- * @param[in] recLength - Lenght of VTOC record
- * @param[in] eccLength - Length of ECC record
+ * @param[in] iterator to VTOC record data
+ * @param[in] iterator to VTOC ECC data
+ * @param[in] Lenght of VTOC record
+ * @param[in] Length of ECC record
*/
- void checkECC(const Binary& tocRecData, const Binary& tocECCData,
+ void checkECC(Binary::const_iterator& itrToRecData,
+ Binary::const_iterator& itrToECCData,
openpower::vpd::constants::RecordLength recLength,
openpower::vpd::constants::ECCLength eccLength);
/** @brief reads value at the given offset
* @param[in] offset - offset value
- * @return[out] - value at that offset in bigendian
+ * @return value at that offset in bigendian
*/
auto getValue(openpower::vpd::constants::offsets::Offsets offset);
@@ -98,7 +99,7 @@
/** @brief update data for given keyword
* @param[in] kwdData- data to be updated
*/
- void updateData(Binary kwdData);
+ void updateData(const Binary& kwdData);
/** @brief update record ECC
*/
@@ -113,8 +114,7 @@
// structure to hold info about record to edit
struct RecInfo
{
- Binary recData;
- Binary recEccData;
+ Binary kwdUpdatedData; // need access to it in case encoding is needed
const std::string& recName;
const std::string& recKWd;
openpower::vpd::constants::RecordOffset recOffset;
@@ -122,15 +122,17 @@
std::size_t recECCLength;
std::size_t kwdDataLength;
openpower::vpd::constants::RecordSize recSize;
-
+ openpower::vpd::constants::DataOffset kwDataOffset;
// constructor
RecInfo(const std::string& rec, const std::string& kwd) :
recName(rec), recKWd(kwd), recOffset(0), recECCoffset(0),
- recECCLength(0), kwdDataLength(0), recSize(0)
+ recECCLength(0), kwdDataLength(0), recSize(0), kwDataOffset(0)
{
}
} thisRecord;
+ Binary vpdFile;
+
}; // class EditorImpl
} // namespace editor
diff --git a/vpd-manager/manager.cpp b/vpd-manager/manager.cpp
index 79ab5a5..766583d 100644
--- a/vpd-manager/manager.cpp
+++ b/vpd-manager/manager.cpp
@@ -84,36 +84,12 @@
}
inventory::Path vpdFilePath = frus.find(path)->second;
- std::ifstream vpdStream(vpdFilePath, std::ios::binary);
- if (!vpdStream)
- {
- throw std::runtime_error("file not found");
- }
- Byte data;
- vpdStream.seekg(IPZ_DATA_START, std::ios::beg);
- vpdStream.get(*(reinterpret_cast<char*>(&data)));
+ // instantiate editor class to update the data
+ EditorImpl edit(vpdFilePath, recordName, keyword);
+ edit.updateKeyword(value);
- // implies it is IPZ VPD
- if (data == KW_VAL_PAIR_START_TAG)
- {
- Binary vpdHeader(lengths::VHDR_RECORD_LENGTH +
- lengths::VHDR_ECC_LENGTH);
- vpdStream.seekg(0);
- vpdStream.read(reinterpret_cast<char*>(vpdHeader.data()),
- vpdHeader.capacity());
-
- // check if header is valid
- openpower::vpd::keyword::editor::processHeader(
- std::move(vpdHeader));
-
- // instantiate editor class to update the data
- EditorImpl edit(vpdFilePath, recordName, keyword);
- edit.updateKeyword(value);
-
- return;
- }
- throw std::runtime_error("Invalid VPD file type");
+ return;
}
catch (const std::exception& e)
{