oem-ibm responder : Implement ReadFile and WriteFile

ReadFile and WriteFile command is required for in-band
file transfers via LPC channel. These commands will be
mostly used for files that are small size.

This commit covers responder for ReadFile and WriteFile.

Change-Id: Id2cbf7afb9aa3ed193376bc93eaae5b8a334d5f7
Signed-off-by: vkaverap <vkaverap@in.ibm.com>
diff --git a/oem/ibm/test/libpldmresponder_fileio_test.cpp b/oem/ibm/test/libpldmresponder_fileio_test.cpp
index d44854f..c132895 100644
--- a/oem/ibm/test/libpldmresponder_fileio_test.cpp
+++ b/oem/ibm/test/libpldmresponder_fileio_test.cpp
@@ -560,3 +560,185 @@
     auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
     ASSERT_EQ(responsePtr->payload[0], PLDM_INVALID_FILE_TABLE_TYPE);
 }
+
+TEST_F(TestFileTable, ReadFileBadPath)
+{
+    uint32_t fileHandle = 1;
+    uint32_t offset = 0;
+    uint32_t length = 0x4;
+
+    std::array<uint8_t, sizeof(pldm_msg_hdr) + PLDM_READ_FILE_REQ_BYTES>
+        requestMsg{};
+    auto requestMsgPtr = reinterpret_cast<pldm_msg*>(requestMsg.data());
+    auto payload_length = requestMsg.size() - sizeof(pldm_msg_hdr);
+    auto request = reinterpret_cast<pldm_read_file_req*>(requestMsg.data() +
+                                                         sizeof(pldm_msg_hdr));
+
+    request->file_handle = fileHandle;
+    request->offset = offset;
+    request->length = length;
+
+    using namespace pldm::filetable;
+    // Initialise the file table with 2 valid file handles 0 & 1.
+    auto& table = buildFileTable(fileTableConfig.c_str());
+
+    // Invalid payload length
+    auto response = readFile(requestMsgPtr, 0);
+    auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
+    ASSERT_EQ(responsePtr->payload[0], PLDM_ERROR_INVALID_LENGTH);
+
+    // Data out of range. File size is 1024, offset = 1024 is invalid.
+    request->offset = 1024;
+
+    response = readFile(requestMsgPtr, payload_length);
+    responsePtr = reinterpret_cast<pldm_msg*>(response.data());
+    ASSERT_EQ(responsePtr->payload[0], PLDM_DATA_OUT_OF_RANGE);
+
+    // Invalid file handle
+    request->file_handle = 2;
+
+    response = readFile(requestMsgPtr, payload_length);
+    responsePtr = reinterpret_cast<pldm_msg*>(response.data());
+    ASSERT_EQ(responsePtr->payload[0], PLDM_INVALID_FILE_HANDLE);
+
+    table.clear();
+}
+
+TEST_F(TestFileTable, ReadFileGoodPath)
+{
+    uint32_t fileHandle = 0;
+    uint32_t offset = 0;
+    uint32_t length = 0x4;
+
+    std::array<uint8_t, sizeof(pldm_msg_hdr) + PLDM_READ_FILE_REQ_BYTES>
+        requestMsg{};
+    auto requestMsgPtr = reinterpret_cast<pldm_msg*>(requestMsg.data());
+    auto payload_length = requestMsg.size() - sizeof(pldm_msg_hdr);
+    auto request = reinterpret_cast<pldm_read_file_req*>(requestMsg.data() +
+                                                         sizeof(pldm_msg_hdr));
+
+    request->file_handle = fileHandle;
+    request->offset = offset;
+    request->length = length;
+
+    using namespace pldm::filetable;
+    // Initialise the file table with 2 valid file handles 0 & 1.
+    auto& table = buildFileTable(fileTableConfig.c_str());
+    FileEntry value{};
+    value = table.at(fileHandle);
+
+    std::ifstream stream(value.fsPath, std::ios::in | std::ios::binary);
+    stream.seekg(offset);
+    std::vector<char> buffer(length);
+    stream.read(buffer.data(), length);
+
+    auto responseMsg = readFile(requestMsgPtr, payload_length);
+    auto response = reinterpret_cast<pldm_read_file_resp*>(
+        responseMsg.data() + sizeof(pldm_msg_hdr));
+    ASSERT_EQ(response->completion_code, PLDM_SUCCESS);
+    ASSERT_EQ(response->length, length);
+    ASSERT_EQ(0, memcmp(response->file_data, buffer.data(), length));
+
+    // Test condition offset + length > fileSize;
+    size_t fileSize = 1024;
+    request->offset = 1023;
+    request->length = 10;
+
+    stream.seekg(request->offset);
+    buffer.resize(fileSize - request->offset);
+    stream.read(buffer.data(), (fileSize - request->offset));
+
+    responseMsg = readFile(requestMsgPtr, payload_length);
+    response = reinterpret_cast<pldm_read_file_resp*>(responseMsg.data() +
+                                                      sizeof(pldm_msg_hdr));
+    ASSERT_EQ(response->completion_code, PLDM_SUCCESS);
+    ASSERT_EQ(response->length, (fileSize - request->offset));
+    ASSERT_EQ(0, memcmp(response->file_data, buffer.data(),
+                        (fileSize - request->offset)));
+
+    table.clear();
+}
+
+TEST_F(TestFileTable, WriteFileBadPath)
+{
+    uint32_t fileHandle = 0;
+    uint32_t offset = 0;
+    uint32_t length = 0x10;
+
+    std::vector<uint8_t> requestMsg(sizeof(pldm_msg_hdr) +
+                                    PLDM_WRITE_FILE_REQ_BYTES + length);
+    auto requestMsgPtr = reinterpret_cast<pldm_msg*>(requestMsg.data());
+    auto payload_length = requestMsg.size() - sizeof(pldm_msg_hdr);
+    auto request = reinterpret_cast<pldm_write_file_req*>(requestMsg.data() +
+                                                          sizeof(pldm_msg_hdr));
+
+    using namespace pldm::filetable;
+    // Initialise the file table with 2 valid file handles 0 & 1.
+    auto& table = buildFileTable(fileTableConfig.c_str());
+
+    request->file_handle = fileHandle;
+    request->offset = offset;
+    request->length = length;
+
+    // Invalid payload length
+    auto response = writeFile(requestMsgPtr, 0);
+    auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
+    ASSERT_EQ(responsePtr->payload[0], PLDM_ERROR_INVALID_LENGTH);
+
+    // Data out of range. File size is 1024, offset = 1024 is invalid.
+    request->offset = 1024;
+
+    response = writeFile(requestMsgPtr, payload_length);
+    responsePtr = reinterpret_cast<pldm_msg*>(response.data());
+    ASSERT_EQ(responsePtr->payload[0], PLDM_DATA_OUT_OF_RANGE);
+
+    // Invalid file handle
+    request->file_handle = 2;
+
+    response = writeFile(requestMsgPtr, payload_length);
+    responsePtr = reinterpret_cast<pldm_msg*>(response.data());
+    ASSERT_EQ(responsePtr->payload[0], PLDM_INVALID_FILE_HANDLE);
+
+    table.clear();
+}
+
+TEST_F(TestFileTable, WriteFileGoodPath)
+{
+    uint32_t fileHandle = 1;
+    uint32_t offset = 0;
+    std::array<uint8_t, 4> fileData = {0x41, 0x42, 0x43, 0x44};
+    uint32_t length = fileData.size();
+
+    std::vector<uint8_t> requestMsg(sizeof(pldm_msg_hdr) +
+                                    PLDM_WRITE_FILE_REQ_BYTES + length);
+    auto requestMsgPtr = reinterpret_cast<pldm_msg*>(requestMsg.data());
+    auto payload_length = requestMsg.size() - sizeof(pldm_msg_hdr);
+    auto request = reinterpret_cast<pldm_write_file_req*>(requestMsg.data() +
+                                                          sizeof(pldm_msg_hdr));
+
+    using namespace pldm::filetable;
+    // Initialise the file table with 2 valid file handles 0 & 1.
+    auto& table = buildFileTable(fileTableConfig.c_str());
+    FileEntry value{};
+    value = table.at(fileHandle);
+
+    request->file_handle = fileHandle;
+    request->offset = offset;
+    request->length = length;
+    memcpy(request->file_data, fileData.data(), fileData.size());
+
+    auto responseMsg = writeFile(requestMsgPtr, payload_length);
+    auto response = reinterpret_cast<pldm_read_file_resp*>(
+        responseMsg.data() + sizeof(pldm_msg_hdr));
+
+    std::ifstream stream(value.fsPath, std::ios::in | std::ios::binary);
+    stream.seekg(offset);
+    std::vector<char> buffer(length);
+    stream.read(buffer.data(), length);
+
+    ASSERT_EQ(response->completion_code, PLDM_SUCCESS);
+    ASSERT_EQ(response->length, length);
+    ASSERT_EQ(0, memcmp(fileData.data(), buffer.data(), length));
+
+    table.clear();
+}