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