1 #include "file_io_by_type.hpp"
2 
3 #include "common/utils.hpp"
4 #include "file_io_type_cert.hpp"
5 #include "file_io_type_dump.hpp"
6 #include "file_io_type_lid.hpp"
7 #include "file_io_type_pcie.hpp"
8 #include "file_io_type_pel.hpp"
9 #include "file_io_type_progress_src.hpp"
10 #include "file_io_type_vpd.hpp"
11 #include "xyz/openbmc_project/Common/error.hpp"
12 
13 #include <libpldm/base.h>
14 #include <libpldm/oem/ibm/file_io.h>
15 #include <stdint.h>
16 #include <unistd.h>
17 
18 #include <phosphor-logging/lg2.hpp>
19 #include <xyz/openbmc_project/Logging/Entry/server.hpp>
20 
21 #include <exception>
22 #include <filesystem>
23 #include <fstream>
24 #include <vector>
25 
26 PHOSPHOR_LOG2_USING;
27 
28 namespace pldm
29 {
30 namespace responder
31 {
32 using namespace sdbusplus::xyz::openbmc_project::Common::Error;
33 
transferFileData(int32_t fd,bool upstream,uint32_t offset,uint32_t & length,uint64_t address)34 int FileHandler::transferFileData(int32_t fd, bool upstream, uint32_t offset,
35                                   uint32_t& length, uint64_t address)
36 {
37     dma::DMA xdmaInterface;
38     while (length > dma::maxSize)
39     {
40         auto rc = xdmaInterface.transferDataHost(fd, offset, dma::maxSize,
41                                                  address, upstream);
42         if (rc < 0)
43         {
44             return PLDM_ERROR;
45         }
46         offset += dma::maxSize;
47         length -= dma::maxSize;
48         address += dma::maxSize;
49     }
50     auto rc = xdmaInterface.transferDataHost(fd, offset, length, address,
51                                              upstream);
52     return rc < 0 ? PLDM_ERROR : PLDM_SUCCESS;
53 }
54 
transferFileDataToSocket(int32_t fd,uint32_t & length,uint64_t address)55 int FileHandler::transferFileDataToSocket(int32_t fd, uint32_t& length,
56                                           uint64_t address)
57 {
58     dma::DMA xdmaInterface;
59     while (length > dma::maxSize)
60     {
61         auto rc = xdmaInterface.transferHostDataToSocket(fd, dma::maxSize,
62                                                          address);
63         if (rc < 0)
64         {
65             return PLDM_ERROR;
66         }
67         length -= dma::maxSize;
68         address += dma::maxSize;
69     }
70     auto rc = xdmaInterface.transferHostDataToSocket(fd, length, address);
71     return rc < 0 ? PLDM_ERROR : PLDM_SUCCESS;
72 }
73 
transferFileData(const fs::path & path,bool upstream,uint32_t offset,uint32_t & length,uint64_t address)74 int FileHandler::transferFileData(const fs::path& path, bool upstream,
75                                   uint32_t offset, uint32_t& length,
76                                   uint64_t address)
77 {
78     bool fileExists = false;
79     if (upstream)
80     {
81         fileExists = fs::exists(path);
82         if (!fileExists)
83         {
84             error("File '{PATH}' does not exist.", "PATH", path);
85             return PLDM_INVALID_FILE_HANDLE;
86         }
87 
88         size_t fileSize = fs::file_size(path);
89         if (offset >= fileSize)
90         {
91             error(
92                 "Offset '{OFFSET}' exceeds file size '{SIZE}' for file handle {FILE_HANDLE}",
93                 "OFFSET", offset, "SIZE", fileSize, "FILE_HANDLE", fileHandle);
94             return PLDM_DATA_OUT_OF_RANGE;
95         }
96         if (offset + length > fileSize)
97         {
98             length = fileSize - offset;
99         }
100     }
101 
102     int flags{};
103     if (upstream)
104     {
105         flags = O_RDONLY;
106     }
107     else if (fileExists)
108     {
109         flags = O_RDWR;
110     }
111     else
112     {
113         flags = O_WRONLY;
114     }
115     int file = open(path.string().c_str(), flags);
116     if (file == -1)
117     {
118         error("File '{PATH}' does not exist.", "PATH", path);
119         return PLDM_ERROR;
120     }
121     utils::CustomFD fd(file);
122 
123     return transferFileData(fd(), upstream, offset, length, address);
124 }
125 
getHandlerByType(uint16_t fileType,uint32_t fileHandle)126 std::unique_ptr<FileHandler> getHandlerByType(uint16_t fileType,
127                                               uint32_t fileHandle)
128 {
129     switch (fileType)
130     {
131         case PLDM_FILE_TYPE_PEL:
132         {
133             return std::make_unique<PelHandler>(fileHandle);
134         }
135         case PLDM_FILE_TYPE_LID_PERM:
136         {
137             return std::make_unique<LidHandler>(fileHandle, true);
138         }
139         case PLDM_FILE_TYPE_LID_TEMP:
140         {
141             return std::make_unique<LidHandler>(fileHandle, false);
142         }
143         case PLDM_FILE_TYPE_LID_MARKER:
144         {
145             return std::make_unique<LidHandler>(fileHandle, false,
146                                                 PLDM_FILE_TYPE_LID_MARKER);
147         }
148         case PLDM_FILE_TYPE_DUMP:
149         case PLDM_FILE_TYPE_RESOURCE_DUMP_PARMS:
150         case PLDM_FILE_TYPE_RESOURCE_DUMP:
151         {
152             return std::make_unique<DumpHandler>(fileHandle, fileType);
153         }
154         case PLDM_FILE_TYPE_CERT_SIGNING_REQUEST:
155         case PLDM_FILE_TYPE_SIGNED_CERT:
156         case PLDM_FILE_TYPE_ROOT_CERT:
157         {
158             return std::make_unique<CertHandler>(fileHandle, fileType);
159         }
160         case PLDM_FILE_TYPE_PROGRESS_SRC:
161         {
162             return std::make_unique<ProgressCodeHandler>(fileHandle);
163         }
164         case PLDM_FILE_TYPE_LID_RUNNING:
165         {
166             return std::make_unique<LidHandler>(fileHandle, false,
167                                                 PLDM_FILE_TYPE_LID_RUNNING);
168         }
169         case PLDM_FILE_TYPE_PSPD_VPD_PDD_KEYWORD:
170         {
171             return std::make_unique<keywordHandler>(fileHandle, fileType);
172         }
173         case PLDM_FILE_TYPE_PCIE_TOPOLOGY:
174         case PLDM_FILE_TYPE_CABLE_INFO:
175         {
176             return std::make_unique<PCIeInfoHandler>(fileHandle, fileType);
177         }
178         default:
179         {
180             throw InternalFailure();
181             break;
182         }
183     }
184     return nullptr;
185 }
186 
readFile(const std::string & filePath,uint32_t offset,uint32_t & length,Response & response)187 int FileHandler::readFile(const std::string& filePath, uint32_t offset,
188                           uint32_t& length, Response& response)
189 {
190     if (!fs::exists(filePath))
191     {
192         error("File '{PATH}' and handle {FILE_HANDLE} does not exist", "PATH",
193               filePath, "FILE_HANDLE", fileHandle);
194         return PLDM_INVALID_FILE_HANDLE;
195     }
196 
197     size_t fileSize = fs::file_size(filePath);
198     if (offset >= fileSize)
199     {
200         error(
201             "Offset '{OFFSET}' exceeds file size '{SIZE}' and file handle '{FILE_HANDLE}'",
202             "OFFSET", offset, "SIZE", fileSize, "FILE_HANDLE", fileHandle);
203         return PLDM_DATA_OUT_OF_RANGE;
204     }
205 
206     if (offset + length > fileSize)
207     {
208         length = fileSize - offset;
209     }
210 
211     size_t currSize = response.size();
212     response.resize(currSize + length);
213     auto filePos = reinterpret_cast<char*>(response.data());
214     filePos += currSize;
215     std::ifstream stream(filePath, std::ios::in | std::ios::binary);
216     if (stream)
217     {
218         stream.seekg(offset);
219         stream.read(filePos, length);
220         return PLDM_SUCCESS;
221     }
222     error(
223         "Unable to read file '{PATH}' at offset '{OFFSET}' for length '{LENGTH}'",
224         "PATH", filePath, "OFFSET", offset, "LENGTH", length);
225     return PLDM_ERROR;
226 }
227 
228 } // namespace responder
229 } // namespace pldm
230