blob: 9661e4e551afd66bee6e23c1f6d5a36275c9d25e [file] [log] [blame] [edit]
#include "pdr_file.hpp"
#include <libpldm/entity.h>
#include <phosphor-logging/lg2.hpp>
PHOSPHOR_LOG2_USING;
namespace pldm
{
namespace responder
{
namespace pdr_file
{
using Json = nlohmann::json;
void generateFileDescriptorPDR(
const Json& json, std::map<uint16_t, FileInfo>& fileIdentifierToFileInfo,
std::map<uint32_t, FileInfo>& recordHandleToFileInfo,
pdr_utils::RepoInterface& repo)
{
static const std::vector<Json> emptyList{};
auto entries = json.value("entries", emptyList);
for (const auto& e : entries)
{
auto entityTypeIt = e.find("EntityType");
if (entityTypeIt == e.end() || !entityTypeIt->is_number())
{
error("EntityType is missing or it is not a number.");
continue;
}
uint16_t entityType = static_cast<uint16_t>(*entityTypeIt);
if ((entityType != PLDM_ENTITY_DEVICE_FILE) &&
(entityType != PLDM_ENTITY_DEVICE_FILE_DIRECTORY))
{
error(
"Invalid EntityType '{ENTITY_TYPE}' for file descriptor PDR. Expected 9 or 10.",
"ENTITY_TYPE", entityType);
continue;
}
auto pathIt = e.find("Path");
if (pathIt == e.end() || !pathIt->is_string())
{
error("'Path' is missing or it is not a string.");
continue;
}
uint16_t container_id = e.value("container", 0);
auto files = e.value("Files", emptyList);
for (const auto& file : files)
{
auto fileIdIt = file.find("FileIdentifier");
if (fileIdIt == file.end() || !fileIdIt->is_number())
{
error("FileIdentifier is missing or it is not a number.");
continue;
}
auto fileNameIt = file.find("FileName");
if (fileNameIt == file.end() || !fileNameIt->is_string())
{
error("FileName is missing or it is not a string.");
continue;
}
auto fileSizeIt = file.find("FileSize");
if (fileSizeIt == file.end() || !fileSizeIt->is_number())
{
error("FileSize is missing or it is not a string.");
continue;
}
const std::string& fileName = fileNameIt.value();
int fileNameLengthWithNull = fileName.length() + 1;
// Calculate the total length of the PDR including the common PDR
// header size. For now this skips the
// OemFileClassificationNameLength and OemFileClassificationName
// since they are not included.
size_t pdrSize = PLDM_PDR_FILE_DESCRIPTOR_PDR_MIN_LENGTH +
fileNameLengthWithNull;
pldm_platform_file_descriptor_pdr pdr{};
// This will be assigned automatically by PDR repository.
pdr.hdr.record_handle = 0;
pdr.hdr.version = 1;
pdr.hdr.type = PLDM_FILE_DESCRIPTOR_PDR;
pdr.hdr.record_change_num = 0;
pdr.hdr.length = pdrSize - sizeof(pldm_pdr_hdr);
pdr.terminus_handle = TERMINUS_HANDLE;
pdr.file_identifier = *fileIdIt;
pdr.container.entity_type = entityType;
pdr.container.entity_instance_num = file.value("InstanceNumber", 0);
pdr.container.entity_container_id = container_id;
pdr.superior_directory_file_identifier =
file.value("SuperiorDirectoryFileIdentifier", 0);
pdr.file_classification = file.value("FileClassification", 0);
pdr.oem_file_classification = 0;
pdr.file_capabilities.value = file.value("FileCapabilities", 0);
pdr.file_maximum_size = fileSizeIt.value();
pdr.file_maximum_file_descriptor_count =
file.value("MaxFileDescriptors", 0);
pdr.file_name.ptr =
reinterpret_cast<const uint8_t*>(fileName.c_str());
pdr.file_name.length = fileNameLengthWithNull;
pdr.oem_file_classification_name.ptr = nullptr;
pdr.oem_file_classification_name.length = 0;
std::vector<uint8_t> entry{};
entry.resize(pdrSize);
size_t pdrSizeCopy = pdrSize;
int ret = encode_pldm_platform_file_descriptor_pdr(
&pdr, entry.data(), &pdrSizeCopy);
if (ret != 0)
{
error("Failed to encode file descriptor PDR for '{FILE_NAME}'",
"FILE_NAME", fileName);
continue;
}
FileInfo fileInfo{};
// Try opening the file here. If the open fail, we will not save the
// PDR. If we do open the file later on, PDR information and the
// actual file might not be in sync.
fileInfo.filePath = pathIt->get<std::string>() + "/" + fileName;
FILE* fp = fopen(fileInfo.filePath.c_str(), "rb");
if (fp == nullptr)
{
error("Failed to open file '{FILE_PATH}'", "FILE_PATH",
fileInfo.filePath);
continue;
}
// This file pointer will be kept open through out the lifetime of
// the program
// TODO: If the file changes during runtime, we need to load it
// again. At that time we will close this and open a file pointer to
// the new file.
fileInfo.fp = fp;
fileInfo.fileIdentifier = *fileIdIt;
fileInfo.fileSize = fileSizeIt.value();
pdr_utils::PdrEntry pdrEntry{};
pdrEntry.data = entry.data();
pdrEntry.size = pdrSize;
pdr_utils::RecordHandle recordHandle;
try
{
recordHandle = repo.addRecord(pdrEntry);
}
catch (const std::runtime_error& e)
{
error("Error adding record for file '{FILE_PATH}'", "FILE_PATH",
fileInfo.filePath);
continue;
}
fileInfo.recordHandle = static_cast<uint32_t>(recordHandle);
fileIdentifierToFileInfo.try_emplace(*fileIdIt, fileInfo);
recordHandleToFileInfo.try_emplace(
static_cast<uint32_t>(recordHandle), fileInfo);
}
}
}
} // namespace pdr_file
} // namespace responder
} // namespace pldm