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 "xyz/openbmc_project/Common/error.hpp"
14 
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 
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 =
50         xdmaInterface.transferDataHost(fd, offset, length, address, upstream);
51     return rc < 0 ? PLDM_ERROR : PLDM_SUCCESS;
52 }
53 
54 int FileHandler::transferFileData(const fs::path& path, bool upstream,
55                                   uint32_t offset, uint32_t& length,
56                                   uint64_t address)
57 {
58     bool fileExists = false;
59     if (upstream)
60     {
61         fileExists = fs::exists(path);
62         if (!fileExists)
63         {
64             std::cerr << "File does not exist. PATH=" << path.c_str() << "\n";
65             return PLDM_INVALID_FILE_HANDLE;
66         }
67 
68         size_t fileSize = fs::file_size(path);
69         if (offset >= fileSize)
70         {
71             std::cerr << "Offset exceeds file size, OFFSET=" << offset
72                       << " FILE_SIZE=" << fileSize << "\n";
73             return PLDM_DATA_OUT_OF_RANGE;
74         }
75         if (offset + length > fileSize)
76         {
77             length = fileSize - offset;
78         }
79     }
80 
81     int flags{};
82     if (upstream)
83     {
84         flags = O_RDONLY;
85     }
86     else if (fileExists)
87     {
88         flags = O_RDWR;
89     }
90     else
91     {
92         flags = O_WRONLY;
93     }
94     int file = open(path.string().c_str(), flags);
95     if (file == -1)
96     {
97         std::cerr << "File does not exist, PATH = " << path.string() << "\n";
98         ;
99         return PLDM_ERROR;
100     }
101     utils::CustomFD fd(file);
102 
103     return transferFileData(fd(), upstream, offset, length, address);
104 }
105 
106 std::unique_ptr<FileHandler> getHandlerByType(uint16_t fileType,
107                                               uint32_t fileHandle)
108 {
109     switch (fileType)
110     {
111         case PLDM_FILE_TYPE_PEL:
112         {
113             return std::make_unique<PelHandler>(fileHandle);
114             break;
115         }
116         case PLDM_FILE_TYPE_LID_PERM:
117         {
118             return std::make_unique<LidHandler>(fileHandle, true);
119             break;
120         }
121         case PLDM_FILE_TYPE_LID_TEMP:
122         {
123             return std::make_unique<LidHandler>(fileHandle, false);
124             break;
125         }
126         case PLDM_FILE_TYPE_DUMP:
127         {
128             return std::make_unique<DumpHandler>(fileHandle);
129             break;
130         }
131         case PLDM_FILE_TYPE_CERT_SIGNING_REQUEST:
132         case PLDM_FILE_TYPE_SIGNED_CERT:
133         case PLDM_FILE_TYPE_ROOT_CERT:
134         {
135             return std::make_unique<CertHandler>(fileHandle, fileType);
136             break;
137         }
138         default:
139         {
140             throw InternalFailure();
141             break;
142         }
143     }
144     return nullptr;
145 }
146 
147 int FileHandler::readFile(const std::string& filePath, uint32_t offset,
148                           uint32_t& length, Response& response)
149 {
150     if (!fs::exists(filePath))
151     {
152         std::cerr << "File does not exist, HANDLE=" << fileHandle
153                   << " PATH=" << filePath.c_str() << "\n";
154         return PLDM_INVALID_FILE_HANDLE;
155     }
156 
157     size_t fileSize = fs::file_size(filePath);
158     if (offset >= fileSize)
159     {
160         std::cerr << "Offset exceeds file size, OFFSET=" << offset
161                   << " FILE_SIZE=" << fileSize << "\n";
162         return PLDM_DATA_OUT_OF_RANGE;
163     }
164 
165     if (offset + length > fileSize)
166     {
167         length = fileSize - offset;
168     }
169 
170     size_t currSize = response.size();
171     response.resize(currSize + length);
172     auto filePos = reinterpret_cast<char*>(response.data());
173     filePos += currSize;
174     std::ifstream stream(filePath, std::ios::in | std::ios::binary);
175     if (stream)
176     {
177         stream.seekg(offset);
178         stream.read(filePos, length);
179         return PLDM_SUCCESS;
180     }
181     std::cerr << "Unable to read file, FILE=" << filePath.c_str() << "\n";
182     return PLDM_ERROR;
183 }
184 
185 } // namespace responder
186 } // namespace pldm
187