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