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 {
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 
122 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 
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