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