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