1 #include "file_table.hpp"
2
3 #include <libpldm/utils.h>
4
5 #include <phosphor-logging/lg2.hpp>
6
7 #include <fstream>
8
9 PHOSPHOR_LOG2_USING;
10
11 namespace pldm
12 {
13 namespace filetable
14 {
FileTable(const std::string & fileTableConfigPath)15 FileTable::FileTable(const std::string& fileTableConfigPath)
16 {
17 std::ifstream jsonFile(fileTableConfigPath);
18 if (!jsonFile.is_open())
19 {
20 error("File table config file '{PATH}' does not exist", "PATH",
21 fileTableConfigPath);
22 return;
23 }
24
25 auto data = Json::parse(jsonFile, nullptr, false);
26 if (data.is_discarded())
27 {
28 error("Failed to parse config file '{PATH}'", "PATH",
29 fileTableConfigPath);
30 return;
31 }
32
33 uint16_t fileNameLength = 0;
34 uint32_t fileSize = 0;
35 uint32_t traits = 0;
36 size_t tableSize = 0;
37 Handle handle = 0;
38 auto iter = fileTable.begin();
39
40 // Iterate through each JSON object in the config file
41 for (const auto& record : data)
42 {
43 constexpr auto path = "path";
44 constexpr auto fileTraits = "file_traits";
45
46 std::string filepath = record.value(path, "");
47 traits = static_cast<uint32_t>(record.value(fileTraits, 0));
48
49 // Split the filepath string using ',' as a delimiter
50 // as the json can define multiple paths to try and use
51 // in order of priority
52 std::istringstream stringstream(filepath);
53 std::string path_substr;
54 fs::path fsPath;
55 while (std::getline(stringstream, path_substr, ','))
56 {
57 fsPath.assign(path_substr);
58 if (fs::exists(fsPath))
59 {
60 break;
61 }
62 }
63
64 // Skip file table entry if it is not a regular file
65 if (!fs::is_regular_file(fsPath))
66 {
67 continue;
68 }
69
70 fileNameLength =
71 static_cast<uint16_t>(fsPath.filename().string().size());
72 fileSize = static_cast<uint32_t>(fs::file_size(fsPath));
73 tableSize = fileTable.size();
74
75 fileTable.resize(tableSize + sizeof(handle) + sizeof(fileNameLength) +
76 fileNameLength + sizeof(fileSize) + sizeof(traits));
77 iter = fileTable.begin() + tableSize;
78
79 // Populate the file table with the contents of the JSON entry
80 std::copy_n(reinterpret_cast<uint8_t*>(&handle), sizeof(handle), iter);
81 std::advance(iter, sizeof(handle));
82
83 std::copy_n(reinterpret_cast<uint8_t*>(&fileNameLength),
84 sizeof(fileNameLength), iter);
85 std::advance(iter, sizeof(fileNameLength));
86
87 std::copy_n(reinterpret_cast<const uint8_t*>(fsPath.filename().c_str()),
88 fileNameLength, iter);
89 std::advance(iter, fileNameLength);
90
91 std::copy_n(reinterpret_cast<uint8_t*>(&fileSize), sizeof(fileSize),
92 iter);
93 std::advance(iter, sizeof(fileSize));
94
95 std::copy_n(reinterpret_cast<uint8_t*>(&traits), sizeof(traits), iter);
96 std::advance(iter, sizeof(traits));
97
98 // Create the file entry for the JSON entry
99 FileEntry entry{};
100 entry.handle = handle;
101 entry.fsPath = std::move(fsPath);
102 entry.traits.value = traits;
103
104 // Insert the file entries in the map
105 tableEntries.emplace(handle, std::move(entry));
106 handle++;
107 }
108
109 constexpr uint8_t padWidth = 4;
110 tableSize = fileTable.size();
111 // Add pad bytes
112 if ((tableSize % padWidth) != 0)
113 {
114 padCount = padWidth - (tableSize % padWidth);
115 fileTable.resize(tableSize + padCount, 0);
116 }
117
118 // Calculate the checksum
119 checkSum = crc32(fileTable.data(), fileTable.size());
120 }
121
operator ()() const122 Table FileTable::operator()() const
123 {
124 Table table(fileTable);
125 table.resize(fileTable.size() + sizeof(checkSum));
126 auto iter = table.begin() + fileTable.size();
127 std::copy_n(reinterpret_cast<const uint8_t*>(&checkSum), sizeof(checkSum),
128 iter);
129 return table;
130 }
131
buildFileTable(const std::string & fileTablePath)132 FileTable& buildFileTable(const std::string& fileTablePath)
133 {
134 static FileTable table;
135 if (table.isEmpty())
136 {
137 table = FileTable(fileTablePath);
138 }
139 return table;
140 }
141
142 } // namespace filetable
143 } // namespace pldm
144