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