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