1 #include "config.h"
2 
3 #include "file_io_by_type.hpp"
4 
5 #include "libpldm/base.h"
6 #include "oem/ibm/libpldm/file_io.h"
7 
8 #include "common/utils.hpp"
9 #include "file_io_type_cert.hpp"
10 #include "file_io_type_dump.hpp"
11 #include "file_io_type_lid.hpp"
12 #include "file_io_type_pel.hpp"
13 #include "file_io_type_progress_src.hpp"
14 #include "xyz/openbmc_project/Common/error.hpp"
15 
16 #include <stdint.h>
17 #include <unistd.h>
18 
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 namespace pldm
28 {
29 namespace responder
30 {
31 
32 using namespace sdbusplus::xyz::openbmc_project::Common::Error;
33 
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 =
51         xdmaInterface.transferDataHost(fd, offset, length, address, upstream);
52     return rc < 0 ? PLDM_ERROR : PLDM_SUCCESS;
53 }
54 
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 =
62             xdmaInterface.transferHostDataToSocket(fd, dma::maxSize, 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 
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             std::cerr << "File does not exist. PATH=" << path.c_str() << "\n";
85             return PLDM_INVALID_FILE_HANDLE;
86         }
87 
88         size_t fileSize = fs::file_size(path);
89         if (offset >= fileSize)
90         {
91             std::cerr << "Offset exceeds file size, OFFSET=" << offset
92                       << " FILE_SIZE=" << fileSize << "\n";
93             return PLDM_DATA_OUT_OF_RANGE;
94         }
95         if (offset + length > fileSize)
96         {
97             length = fileSize - offset;
98         }
99     }
100 
101     int flags{};
102     if (upstream)
103     {
104         flags = O_RDONLY;
105     }
106     else if (fileExists)
107     {
108         flags = O_RDWR;
109     }
110     else
111     {
112         flags = O_WRONLY;
113     }
114     int file = open(path.string().c_str(), flags);
115     if (file == -1)
116     {
117         std::cerr << "File does not exist, PATH = " << path.string() << "\n";
118         ;
119         return PLDM_ERROR;
120     }
121     utils::CustomFD fd(file);
122 
123     return transferFileData(fd(), upstream, offset, length, address);
124 }
125 
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         default:
165         {
166             throw InternalFailure();
167             break;
168         }
169     }
170     return nullptr;
171 }
172 
173 int FileHandler::readFile(const std::string& filePath, uint32_t offset,
174                           uint32_t& length, Response& response)
175 {
176     if (!fs::exists(filePath))
177     {
178         std::cerr << "File does not exist, HANDLE=" << fileHandle
179                   << " PATH=" << filePath.c_str() << "\n";
180         return PLDM_INVALID_FILE_HANDLE;
181     }
182 
183     size_t fileSize = fs::file_size(filePath);
184     if (offset >= fileSize)
185     {
186         std::cerr << "Offset exceeds file size, OFFSET=" << offset
187                   << " FILE_SIZE=" << fileSize << "\n";
188         return PLDM_DATA_OUT_OF_RANGE;
189     }
190 
191     if (offset + length > fileSize)
192     {
193         length = fileSize - offset;
194     }
195 
196     size_t currSize = response.size();
197     response.resize(currSize + length);
198     auto filePos = reinterpret_cast<char*>(response.data());
199     filePos += currSize;
200     std::ifstream stream(filePath, std::ios::in | std::ios::binary);
201     if (stream)
202     {
203         stream.seekg(offset);
204         stream.read(filePos, length);
205         return PLDM_SUCCESS;
206     }
207     std::cerr << "Unable to read file, FILE=" << filePath.c_str() << "\n";
208     return PLDM_ERROR;
209 }
210 
211 } // namespace responder
212 } // namespace pldm
213